Deploy Azure Batch via ARM template with application upload - azure

I built out an Azure Batch Account via the UI (Portal) and exported the template after I got everything working the way I wanted it.
Now I'm trying to deploy this ARM template via Visual Studio 2019 and keep getting the following error:
The specified application package does not exist.
The ARM template looks good and I've reconciled it with Microsoft.Batch batchAccounts/pools template reference. I did this to verify that the template allows for applicationPackages element.
The specific portion of the template causing my issue is as follows:
"applicationPackages": [
{
"id": "[concat(resourceId('Microsoft.Batch/batchAccounts', parameters('batchAccounts_baeast909_name')), '/applications/logparser')]",
"version": "2.2"
},
{
"id": "[concat(resourceId('Microsoft.Batch/batchAccounts', parameters('batchAccounts_baeast909_name')), '/applications/powershellscripts')]",
"version": "1.0"
}
]
I was hoping this is would be as simple as placing the application zips in a directory called applications and running everything again. Alas it wasn't and the deployment failed with the same error.
One of the comments asked why I would be doing this. The answer to this is I'm running a Custom Activity out of Azure Data Factory V2 (ADFv2.) The custom activity transforms WebLogs via a executable called LogParser.exe That executable is loaded as an application to the Batch Account as you see below. I also added the PowerShell Scripts that tie everything together as an application.
I was hoping for a solution similar to deploying a Web App that is detailed here: Deploy Azure Web App Package using ARM
So my questions are:
Can the applications zips be deployed at the same time as I am deploying the ARM template?
If they can not, when do I deploy them, and how do I automate that process?
application.json:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"configuration": {
"type": "object",
"metadata": {
"description": "Configuration for this resource"
}
},
"pools_1_password": {
"type": "SecureString"
},
"batchAccounts_baeast909_name": {
"defaultValue": "baeast909",
"type": "String"
},
"storageAccounts_storageaccount909_externalid": {
"defaultValue": "/subscriptions/subguid/resourceGroups/resourcegroup909/providers/Microsoft.Storage/storageAccounts/storageaccount909",
"type": "String"
}
},
"variables": {},
"resources": [
{
"type": "Microsoft.Batch/batchAccounts",
"apiVersion": "2017-09-01",
"name": "[parameters('batchAccounts_baeast909_name')]",
"location": "eastus2",
"tags": {
"displayname": "[parameters('configuration').displayName]",
"department": "[parameters('configuration').department]",
"group": "[parameters('configuration').group]",
"environment": "[parameters('configuration').environment]",
"primaryOwner": "[parameters('configuration').primaryOwner]",
"secondaryOwner": "[parameters('configuration').secondaryOwner]",
"version": "[parameters('configuration').version]",
"ms-resource-usage": "azure-cloud-shell"
},
"properties": {
"autoStorage": {
"storageAccountId": "[parameters('storageAccounts_storageaccount909_externalid')]"
},
"poolAllocationMode": "BatchService"
}
},
{
"type": "Microsoft.Batch/batchAccounts/pools",
"apiVersion": "2017-09-01",
"name": "[concat(parameters('batchAccounts_baeast909_name'), '/1')]",
"dependsOn": [
"[resourceId('Microsoft.Batch/batchAccounts', parameters('batchAccounts_baeast909_name'))]"
],
"properties": {
"vmSize": "STANDARD_A1",
"interNodeCommunication": "Disabled",
"maxTasksPerNode": 1,
"taskSchedulingPolicy": {
"nodeFillType": "Spread"
},
"deploymentConfiguration": {
"virtualMachineConfiguration": {
"imageReference": {
"publisher": "microsoftwindowsserver",
"offer": "windowsserver",
"sku": "2016-datacenter",
"version": "latest"
},
"nodeAgentSkuId": "batch.node.windows amd64",
"dataDisks": [
{
"lun": 0,
"caching": "ReadWrite",
"diskSizeGB": 100,
"storageAccountType": "Standard_LRS"
}
]
}
},
"scaleSettings": {
"fixedScale": {
"targetDedicatedNodes": 1,
"targetLowPriorityNodes": 0,
"resizeTimeout": "PT15M"
}
},
"userAccounts": [
{
"name": "jborn",
"elevationLevel": "NonAdmin",
"password": "[parameters('pools_1_password')]"
}
],
"applicationPackages": [
{
"id": "[concat(resourceId('Microsoft.Batch/batchAccounts', parameters('batchAccounts_baeast909_name')), '/applications/logparser')]",
"version": "2.2"
},
{
"id": "[concat(resourceId('Microsoft.Batch/batchAccounts', parameters('batchAccounts_baeast909_name')), '/applications/powershellscripts')]",
"version": "1.0"
}
]
}
}
]
}
application.parameters.json:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"configuration": {
"value": {
"displayName": "A Batch Account",
"department": "IT",
"group": "Development",
"environment": "dev",
"primaryOwner": "user1#fred.com",
"secondaryOwner": "user2#fred.com",
"version": "1.0"
}
},
"pools_1_password": {
"reference": {
"keyVault": {
"id": "/subscriptions/subguid/resourceGroups/rgn00119/providers/Microsoft.KeyVault/vaults/keyvault909"
},
"secretName": "azureAdmin"
}
},
"batchAccounts_jc00mdpbageu2d99_name": {
"value": "jc00mdpbageu2d99"
},
"storageAccounts_jc00mdpstgeud99_externalid": {
"value": "/subscriptions/subguid/resourceGroups/rgn00119/providers/Microsoft.Storage/storageAccounts/storageAccount909"
}
}
}

Please follow the below steps to download and deploy an ARM template using Visual Studio 2019:
Fill the details for creating a Azure Batch account and click on "Download a template for automation"
Download the zip
Deploy ARM template using Visual Studio 2019
https://learn.microsoft.com/en-us/azure/azure-resource-manager/vs-azure-tools-resource-groups-deployment-projects-create-deploy
In step 4 in the above document use a blank template instead of a WebApp
Now paste the contents from the downloaded zip
Copy contents from template.json to azuredeploy.json
Copy contents from parameters.json to azuredeploy.parameters.json
Now deploy your ARM template using https://learn.microsoft.com/en-us/azure/azure-resource-manager/vs-azure-tools-resource-groups-deployment-projects-create-deploy#azurerm-module-script
Edit: In order to create a batch pool using ARM template, you would first have to create an Application Package using Azure CLI and reference this from your ARM template for creating a Batch Pool
# Upload and register your archive as application package
az batch application package create \
--resource-group testrg01 \
--name test01 \
--application-id app01 \
--package-file myapp-exe.zip \
--version 1.0
# Set this version of package as default version
az batch application set \
--resource-group testrg01 \
--name test01 \
--application-id app01 \
--default-version 1.0
References:
https://tsmatz.wordpress.com/2017/12/12/essential-azure-batch-with-azure-cli/
https://learn.microsoft.com/bs-latn-ba/cli/azure/batch/application/package?view=azure-cli-latest
https://learn.microsoft.com/en-us/azure/batch/batch-cli-templates
Hope this helps!

Related

Workflow deployment with enabling Log Analytics in Azure Logic App using Rest API

I am trying to deploy workflows in Azure using workflows Rest API's(https://learn.microsoft.com/en-us/rest/api/logic/workflows ). I want to enable Log Analytics Workspace while deploying this workflow in Logic App. This is straight forward in portal while creating logic app. But I didn't find any document or information to pass log analytics workspace while creating workflow definition(JSON File). Please let me know, if there is a way to pass it
In a comment above you mentioned "If it's possible in ARM Template, then I am fine with it and I will use ARM Template deployment API's to deploy it."
Here's an example, feel free to amend it so that it suits your needs:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"logicapp-name": {
"type": "string",
"defaultValue": "testLogicApp",
"metadata": {
"description": "Name of the Logic App"
}
},
"loganalytics-workspace-resourceid": {
"type": "string",
"defaultValue": "/subscriptions/11111111-2222-3333-4444-555555555555/resourcegroups/testResourceGroup/providers/microsoft.operationalinsights/workspaces/testLogAnalyticsWorkspace",
"metadata": {
"description": "Resource ID of the Log Analytics workspace"
}
}
},
"variables": {
"logAnalyticsSettingName": "testDiagnosticSettingName"
},
"resources": [
{
"type": "Microsoft.Logic/workflows/providers/diagnosticSettings",
"name": "[concat(parameters('logicapp-name'),'/Microsoft.Insights/', variables('logAnalyticsSettingName'))]",
"apiVersion": "2017-05-01-preview",
"properties": {
"workspaceId": "[parameters('loganalytics-workspace-resourceid')]",
"logs": [
{
"category": "WorkflowRuntime",
"enabled": true,
"retentionPolicy": {
"days": 0,
"enabled": false
}
}
],
"metrics": [
{
"timeGrain": "PT1M",
"enabled": true,
"retentionPolicy": {
"enabled": false,
"days": 0
}
}
]
}
}
]
}

ADF ARM Template doesn't appear to include the factory itself

I was in the process of configuring DevOps to deploy my Dev ADF to the UAT ADF instance.
I had come across the standard issue of the deploy not deleting out-dated pipelines, and attempted to use "Complete" deployment mode to resolve that.
Whereupon DevOps entirely deleted the UAT ADF instance!
Looking further at the docs, it appears that this is the expected behaviour if the factories are not in the ARM Templates.
And looking at my ARM Template (generated entirely by ADF, and with [AFAIK] entirely standard settings), it confirms that the factory itself is NOT amongst the documented resources to be created.
This seems ... odd.
Am I missing something?
How do I get the factory to be included in the ARM Template?
Or alternatively, how can I use the "Complete" deployment mode without it deleting the target ADF instance?
Note that the reason I don't want to use the "define a separate script to solve this" approach, is that it seems excessively complex when that the "Complete" mode sounds like it should do exactly what I want :) (If it weren't for this one oddity about deleting the factory)
You are correct. I've run into this issue before. To circumnavigate it this I recommend creating a core ARM template that would contain the Data Factory and any necessary linked services solely used by Data Factory. This will ensure the "infrastructure/connections" are deployed when creating a new instance.
If you are following Azure Data Factory CI/CD this would be an additional Azure Resource Group Deployment task before the Pipelines are deployed and reference the ARM template which should be in a separate repository.
Here's a template for Data Factory w/ Log Analytics to get you started. I included Log Analytics as most people don't realize about Log retention until they need it. Plus it's a best practices. Just update the system name as this will create a naming standard of adf-systemName-environment-regionAbrviation. The region abbreviation is dynamic based upon the object and will look up agianst the resource group.
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"environment": {
"type": "string",
"metadata": "Name of the environment being deployed to"
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Location for all resources."
}
}
},
"variables": {
"systemName": "DataFactoryBaseName",
"regionReference": {
"centralus": "cus",
"eastus": "eus",
"westus": "wus"
},
"dataFactoryName": "[toLower(concat('adf-', variables('systemName'),'-', parameters('environment'),'-',variables('regionDeployment')))]",
"logAnalyticsName": "[toLower(concat('law-', variables('systemName'),'-', parameters('environment'),'-',variables('regionDeployment')))]",
"regionDeployment": "[toLower(variables('regionReference')[parameters('location')])]"
},
"resources": [
{
"name": "[variables('dataFactoryName')]",
"type": "Microsoft.DataFactory/factories",
"apiVersion": "2018-06-01",
"location": "[parameters('location')]",
"tags": {
"displayName": "Data Factory",
"ProjectName": "[variables('systemName')]",
"Environment":"[parameters('environment')]"
},
"identity": {
"type": "SystemAssigned"
}
},
{
"type": "Microsoft.OperationalInsights/workspaces",
"name": "[variables('logAnalyticsName')]",
"tags": {
"displayName": "Log Analytics",
"ProjectName": "[variables('systemName')]",
"Environment":"[parameters('environment')]"
},
"apiVersion": "2020-03-01-preview",
"location": "[parameters('location')]"
},
{
"type": "microsoft.datafactory/factories/providers/diagnosticsettings",
"name": "[concat(variables('dataFactoryName'),'/Microsoft.Insights/diagnostics')]",
"location": "[parameters('location')]",
"apiVersion": "2017-05-01-preview",
"dependsOn": [
"[resourceID('Microsoft.OperationalInsights/workspaces',variables('logAnalyticsName'))]",
"[resourceID('Microsoft.DataFactory/factories',variables('dataFactoryName'))]"
],
"properties": {
"name": "diagnostics",
"workspaceId": "[resourceID('Microsoft.OperationalInsights/workspaces',variables('logAnalyticsName'))]",
"logAnalyticsDestinationType": "Dedicated",
"logs": [
{
"category": "PipelineRuns",
"enabled": true,
"retentionPolicy": {
"enabled": false,
"days": 0
}
},
{
"category": "TriggerRuns",
"enabled": true,
"retentionPolicy": {
"enabled": false,
"days": 0
}
},
{
"category": "ActivityRuns",
"enabled": true,
"retentionPolicy": {
"enabled": false,
"days": 0
}
}
],
"metrics": [
{
"category": "AllMetrics",
"timeGrain": "PT1M",
"enabled": true,
"retentionPolicy": {
"enabled": false,
"days": 0
}
}
]
}
}
]
}

Azure Function+ARM: merge app settings with current settings

My deployment is split into two pipelines
deploy infrastructure (run ARM template)
deploy & configure application (upload app, run script)
My ARM template contains an AppSettings array, like this:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
// ...
},
"variables": {
"functionAppName": "[parameters('appName')]",
"storageAccountid": "[concat(resourceGroup().id,'/providers/','Microsoft.Storage/storageAccounts/', parameters('storageAccountName'))]"
},
"resources": [
{
"apiVersion": "2015-08-01",
"type": "Microsoft.Web/sites",
"name": "[variables('functionAppName')]",
"location": "[parameters('location')]",
"kind": "functionapp",
"dependsOn": [],
"properties": {
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', parameters('hostingPlanName'))]",
"siteConfig": {
"appSettings": [
{
"name": "AzureWebJobsStorage",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', parameters('storageAccountName'), ';AccountKey=', listKeys(variables('storageAccountid'),'2015-05-01-preview').key1)]"
},
{
"name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', parameters('storageAccountName'), ';AccountKey=', listKeys(variables('storageAccountid'),'2015-05-01-preview').key1)]"
},
{
"name": "WEBSITE_CONTENTSHARE",
"value": "[toLower(variables('functionAppName'))]"
},
{
"name": "FUNCTIONS_EXTENSION_VERSION",
"value": "~2"
},
{
"name": "WEBSITE_NODE_DEFAULT_VERSION",
"value": "6.5.0"
},
{
"name": "APPINSIGHTS_INSTRUMENTATIONKEY",
"value": "[reference(resourceId('microsoft.insights/components/', parameters('applicationInsightsName')), '2015-05-01').InstrumentationKey]"
}
]
}
}
}
]
}
During the application deployment, I set new app settings, like this:
az functionapp config appsettings set --resource-group $resourceGroupName
--name $functionAppName --settings "foo=bar"
Whenever the infrastructure pipeline is run, it completely removes all app settings which were added via script (e.g. foo). Is there a way to tell ARM to "merge" the deployed AppSettings with the settings defined by the template? Ideally, this should also work when deploying the ARM template for the very first time.
My current workaround is to simply remove the AppSettings part of the ARM template completely.
No, you cannot have merge behaviour. I dont think you can set individual app setting values with arm templates, so you'd need to put those keys you add at deployment time to the arm template, or remove appsettings from the arm template.

Azure ARM condition fails during validation

In my azure template I have a condition where I chose if I want my webapps deployed on a dedicated App Service Plan or if I want to use a shared App Service plan.
If I chose to not use a dedicated plan I want to ignore:
- the first section where I deploy the dedicated App Service Plan
- the second section where I deploy the Web Apps and use the dedicated Service Plan.
The third section is then used and deploy the web apps with a shared app plan.
Below is an extract of my ARM template.
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"_artifactsLocation": {
"type": "string"
},
"_artifactsLocationSasToken": {
"type": "string"
},
"environmentConfiguration": {
"type": "object"
}
},
"variables": {},
"resources": [
{
"comments": "App Service Plan hosting all websites",
"apiVersion": "2017-05-10",
"name": "AppServicePlan",
"type": "Microsoft.Resources/deployments",
"condition": "[equals(parameters('environmentConfiguration').serverFarm.useDedicatedPlan, 'true')]",
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[concat(parameters('_artifactsLocation'),'/Microsoft.Web/Asp.json',parameters('_artifactsLocationSasToken'))]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"environmentConfiguration": {
"value": "[parameters('environmentConfiguration')]"
}
}
}
},
{
"comments": "Web apps on dedicated plan",
"apiVersion": "2017-05-10",
"name": "[concat('WebAppsDedicatedPlan-',parameters('environmentConfiguration').webApp.webApps[copyIndex()].name)]",
"type": "Microsoft.Resources/deployments",
"condition": "[equals(parameters('environmentConfiguration').serverFarm.useDedicatedPlan, 'true')]",
"copy": {
"name": "webAppCopy",
"count": "[length(parameters('environmentConfiguration').webApp.webApps)]"
},
"dependsOn": [
"[resourceId('Microsoft.Resources/deployments', 'AppServicePlan')]"
],
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[concat(parameters('_artifactsLocation'),'/Microsoft.Web/WebApp.json',parameters('_artifactsLocationSasToken'))]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"environmentConfiguration": {
"value": "[parameters('environmentConfiguration')]"
},
"dependencies": {
"value": {
"webAppInfo": "[parameters('environmentConfiguration').webApp.webApps[copyIndex()]]",
"serverFarmId": "[reference('AppServicePlan').outputs.serverFarmId.value]"
}
}
}
}
},
{
"comments": "Web apps on shared plan",
"apiVersion": "2017-05-10",
"name": "[concat('WebAppsOnSharedPlan-',parameters('environmentConfiguration').webApp.webApps[copyIndex()].name)]",
"type": "Microsoft.Resources/deployments",
"condition": "[equals(parameters('environmentConfiguration').serverFarm.useDedicatedPlan, 'false')]",
"copy": {
"name": "webAppCopy",
"count": "[length(parameters('environmentConfiguration').webApp.webApps)]"
},
"dependsOn": [],
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[concat(parameters('_artifactsLocation'),'/Microsoft.Web/WebApp.json',parameters('_artifactsLocationSasToken'))]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"environmentConfiguration": {
"value": "[parameters('environmentConfiguration')]"
},
"dependencies": {
"value": {
"webAppInfo": "[parameters('environmentConfiguration').webApp.webApps[copyIndex()]]",
"serverFarmId": "[resourceId('sharedResources','Microsoft.Web/serverfarms','sharedasp')]"
}
}
}
}
}
],
"outputs": {}
}
What is working: If I remove the condition in the App Service Plan section and I ask to not use the dedicated plan, my web apps are deployed using the shared plan. (The app service plan is also deployed).
What is not working: If I let the condition in the App Service Plan section to not deploy it when I ask for to not use the dedicated plan the validation fails with the following message:
2017-09-25T11:55:49.7343682Z Creating deployment parameters.
2017-09-25T11:55:49.7373683Z The detected encoding for file
'd:\a\r1\a\output\iac\myapp.json' is 'utf-8'
2017-09-25T11:55:49.7373683Z The detected encoding for file
'd:\a\r1\a\output\iac\myapp.parameters.qa.json' is 'utf-8'
2017-09-25T11:55:49.7373683Z Starting Deployment.
2017-09-25T11:55:51.3725072Z There were errors in your deployment.
Error code: InvalidTemplate. 2017-09-25T11:55:51.3735078Z
##[error]Deployment template validation failed: 'The template resource 'Microsoft.Resources/deployments/WebAppsDedicatedPlan-appadmin'
reference to 'Microsoft.Resources/deployments/AppServicePlan' requires
an API version. Please see https://aka.ms/arm-template for usage
details.'. 2017-09-25T11:55:51.3735078Z ##[error]Task failed while
creating or updating the template deployment.
2017-09-25T11:55:51.4295112Z ##[section]Finishing: Azure Deployment:
Update resource group
How can I solve this issue?
'The template resource
'Microsoft.Resources/deployments/WebAppsDedicatedPlan-appadmin'
reference to 'Microsoft.Resources/deployments/AppServicePlan' requires
an API version.
The error gives that away. Check docs for better understanding. This is why it errors out:
API version of the specified resource. Include this parameter when the resource is not provisioned within same template. Typically, in the format, yyyy-mm-dd.
So you need to add api version to the reference function for resources created outside of the template

Retrieve Service Bus event hub connection string

I have an existing Service Bus with one queue and event hub deployed using Azure Resource Manager.
Now I am interested to retrieve the primary key and connection string using Azure PowerShell wiithout using the ServiceBus.dll. Is it possible??
As a workaround I have created an ARM template which does not deploy anything but just query the existing resource and retrieve the information I need. The below template retrieves the connection string and primary key of an event hub/queue for a specific service bus namespace
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"serviceBusNamespace": {
"type": "string",
"minLength": 1,
"metadata": {
"description": "The name of the service bus namespace to create."
}
},
"resourceName": {
"type": "string",
"minLength": 1,
"metadata": {
"description": "The name of the resource to be retreived."
}
},
"resourceType": {
"type": "string",
"minLength": 1,
"allowedValues": [
"queues",
"eventhubs"
],
"metadata": {
"description": "The type of the resource"
}
},
"policy": {
"type": "string",
"minLength": 1,
"defaultValue": "ManagePolicy",
"allowedValues": [
"ManagePolicy",
"SendPolicy",
"ListenPolicy"
],
"metadata": {
"description": "The type of the resource"
}
}
},
"variables": {
},
"resources": [ ],
"outputs": {
"connectionString": {
"type": "string",
"value": "[listKeys(resourceId(concat('Microsoft.ServiceBus/namespaces/',parameters('resourceType'),'/authorizationRules'),parameters('serviceBusNamespace'),parameters('resourceName'),parameters('policy')),'2015-08-01').primaryConnectionString]"
},
"primaryKey": {
"type": "string",
"value": "[listKeys(resourceId(concat('Microsoft.ServiceBus/namespaces/',parameters('resourceType'),'/authorizationRules'),parameters('serviceBusNamespace'),parameters('resourceName'),parameters('policy')),'2015-08-01').primaryKey]"
}
}
}
Is it abusing to use ARM template to query for a resource and not actually deploy anything?
EDIT
To capture the output of the ARM template within PowerShell use the below code
$ep = New-AzureRmResourceGroupDeployment -Name "getEventHub" -ResourceGroupName myResourceGroup -Mode Incremental -TemplateFile getEventHub.json -TemplateParameterFile getEventHub.param.json
$RuleConnString = $ep.Outputs.connectionString.value
$RulePrimaryKey = $ep.Outputs.primaryKey.value
Note that the property names connectionString and primaryKey are same as defined in my template file
EDIT 2
If I re-run the ARM template to deploy the event hub second time I get the below error.
I din't find any option other than to use the ARM template to query the details.
I don’t see what’s wrong with what you’re doing. In my view Resource Manager templates in their nature are incremental. So you could author a template to create your existing service bus with the same resources. If the properties are the same then it will leave the existing resources intact and return you the connection string and primary key of the relevant resource.
I have a need to automate the creation of a service bus and queue and separate send/listen shared access policies. You can retrieve the connection string on the service bus itself using PowerShell natively without using the .Net ServiceBus.dll assembly by using Get-AzureSBAuthorizationRule but due to a still current bug this doesn’t work at the queue level.
I tried using the ServiceBus.dll to create the shared access policies but sometimes it would randomly fail but subsequently work if you ran it a second time immediately afterwards. I also tried Resource Manager templates but previously you had to pass in the keys you’d generated yourself. Now I see Microsoft generate those for you but you’re still left trying to get the key in an automated fashion so I like your solution.
One question though, can you capture the Resource Manager template outputs and pass them back to a PowerShell script, do you know?
Cheers
Rob
{ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": {
"servicebusNamespace": {
"type": "string",
"metadata": {
"description": "The service bus namespace"
}
},
"notificationssmsqueue": {
"type": "string",
"metadata": {
"description": "Notifications SMS queue"
}
} }, "variables": {
"location": "[resourceGroup().location]", }, "resources": [
{
"apiVersion": "2015-08-01",
"name": "[parameters('servicebusNamespace')]",
"type": "Microsoft.ServiceBus/namespaces",
"location": "[variables('location')]",
"properties": {
"messagingSku": 2
},
"resources": [
{
"apiVersion": "2015-08-01",
"name": "[parameters('notificationssmsqueue')]",
"type": "Queues",
"dependsOn": [
"[concat('Microsoft.ServiceBus/namespaces/', parameters('servicebusNamespace'))]"
],
"properties": {
"path": "[parameters('notificationssmsqueue')]"
},
"resources": [
{
"apiVersion": "2015-08-01",
"name": "[concat(parameters('notificationssmsqueue'),'.listen')]",
"type": "AuthorizationRules",
"dependsOn": [
"[parameters('notificationssmsqueue')]"
],
"properties": {
"keyName": "[concat(parameters('notificationssmsqueue'),'.listen')]",
"claimType": "SharedAccessKey",
"claimValue": "None",
"rights": [ "Listen" ],
"revision": -1
}
},
{
"apiVersion": "2015-08-01",
"name": "[concat(parameters('notificationssmsqueue'),'.send')]",
"type": "AuthorizationRules",
"dependsOn": [
"[parameters('notificationssmsqueue')]"
],
"properties": {
"keyName": "[concat(parameters('notificationssmsqueue'),'.send')]",
"claimType": "SharedAccessKey",
"claimValue": "None",
"rights": [ "Send" ],
"revision": -1
}
}
]
}
]
} ], "outputs": {
"connectionString": {
"type": "string",
"value": "[listKeys(resourceId(concat('Microsoft.ServiceBus/namespaces/AuthorizationRules'),parameters('serviceBusNamespace'),'RootManageSharedAccessKey'),'2015-08-01').primaryConnectionString]"
},
"smsSendPrimaryKey": {
"type": "string",
"value": "[listKeys(resourceId(concat('Microsoft.ServiceBus/namespaces/Queues/AuthorizationRules'),parameters('serviceBusNamespace'),parameters('notificationssmsqueue'),concat(parameters('notificationssmsqueue'),'.send')),'2015-08-01').PrimaryKey]"
},
"smsListenPrimaryKey": {
"type": "string",
"value": "[listKeys(resourceId(concat('Microsoft.ServiceBus/namespaces/Queues/AuthorizationRules'),parameters('serviceBusNamespace'),parameters('notificationssmsqueue'),concat(parameters('notificationssmsqueue'),'.listen')),'2015-08-01').PrimaryKey]"
} } }
But I call my templates like this:
New-AzureRMResourceGroupDeployment -ResourceGroupName $ResourceGroupName -TemplateFile "$scripts_folder$SB_create_script" -TemplateParameterObject `
#{ servicebusNamespace = $servicebusNamespace;
notificationssmsqueue = $NotificationSMSqueue }
This is the correct way to get the information you are seeking. The Resource Manager provides a common interface to interact with all the services. It is how the Portal access the services, and each of the language SDKs are just wrappers for similar requests to the one you have created.
I usually use the Python or java SDKs, but I have been told that NodeJS is a very easy way to wrap the Web APIs that ARM calls to construct similar calls like the one you made, if you are looking for a none ARM way to do this.

Resources