Run Azure Functions from your Quickstart ARM Templates

I was recently confronted with the following problem: how can I run code from inside an Azure ARM Quickstart Template? Well, if you don’t know ARM Templates, they are essentially a declarative description of objects as you want to have them in Azure, but they don’t allow to run code as such. For example, see this question from someone who wanted to send an email notification upon completion of an ARM template.

The immediate answer would be something like creating Logic Apps or Azure Functions from the ARM Template. The problem there is that the template will create those Apps and Functions, but not necessarily run them. You could create them using a scheduled trigger, but then they would run multiple times, and you might want to have them executed only once.

My esteemed colleagued Mike Chen (see him in action here) put me on the right track: ARM Templates do not have a construct to call web APIs, but they do reach out for HTTP URLs when you nest other templates inside. For example, consider this quickstart template:

{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {},
    "variables": {
        "TemplateUri": "https://erjositofunctions.azurewebsites.net/api/fakeARMtemplate"
    },
    "resources": [
        {
            "name": "myNestedTemplate",
            "type": "Microsoft.Resources/deployments",
            "apiVersion": "2016-06-01",
            "properties": {
                "mode": "Incremental",
                "templateLink": {
                    "uri": "[variables('TemplateUri')]",
                    "contentVersion": "1.0.0.0"
                },
                "parameters":  {}
            }
        }
    ]
}

As you have probably realized, this template does nothing else than running another template that is nested inside, and that is reachable under the URL https://erjositofunctions.azurewebsites.net/api/fakeARMtemplate. If you call that link you will get JSON code for an empty ARM template that does nothing at all:

{
    '$schema': 'https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#',
    'contentVersion': '1.0.0.0',
    'parameters': {},
    'variables': {},
    'resources': []
}

So essentially, our initial ARM template calls a URL and downloads another ARM template that does not do anything. Exciting isn’t it?

Well, actually the downloaded ARM template does not do anything, but that does not mean that nothing happens. As you have probably figured out from the URL, when you are calling https://erjositofunctions.azurewebsites.net/api/fakeARMtemplate you are actually running an Azure Function. Here is the function, written in C#:

#r "System.Web"
#r "System.Runtime"
#r "System.Threading.Tasks"
#r "System.IO"
using System;
using System.Net;
using System.Net.Http.Headers;
using System.Collections.Generic;
using System.IO;

public static async Task Run(HttpRequestMessage req, TraceWriter log)
{
   log.Info("C# HTTP trigger function processed a request.");

   // Get request body
   dynamic data = await req.Content.ReadAsAsync();

   //Do whatever you want to do, for example call a webhook with JSON payload
   using (var client = new HttpClient()) 
   { 
       client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
       client.DefaultRequestHeaders.Add("User-Agent", "AzureFunctions");
       var webhookUri = "https://myWebHook.com";
       StringContent webhookBody = new StringContent ("{'text': 'hello World'}");
       HttpResponseMessage response = client.PostAsync(webhookUri,webhookBody).Result; 
       var responseString = response.Content.ReadAsStringAsync().Result;
   }

   //Send back an empty template as JSON code, as answer to the original GET
   var template = @"{'$schema': 'https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#', 'contentVersion': '1.0.0.0', 'parameters': {}, 'variables': {}, 'resources': []}";
   HttpResponseMessage myResponse = req.CreateResponse(HttpStatusCode.OK);
   myResponse.Content = new StringContent(template, System.Text.Encoding.UTF8, "application/json");
   return myResponse;
}

As you can see, other than returning the JSON string with an empty, but syntactically correct ARM template, the Azure Function is calling a Webhook. This could do anything, from triggering another Azure Function, or an Azure Logic App, or whatever your imagination can think of.

Now, the only thing you need to do is adding a nested template deployment pointing to your Azure Function in your existing ARM template (that hopefully does do something), and your Azure Function will run every time the ARM template is deployed.

Your might be wondering now how to pass parameters to the Azure Function. Well, the master template will try to GET the nested template, so you cannot use POST. So you need to pass the arguments in the URI. For example, if you wanted to pass the resource group name where the ARM template is being deployed to, you could use this definition of the URI:

"TemplateUri": "[concat ('https://erjositofunctions.azurewebsites.net/api/fakeARMtemplate', '?resourcegroupname=', resourceGroup().name)]"

And your Function (in this example in C#) would have to extract the parameter to a variable, for example like this:

    // Parse query parameter resourcegroupname
    string resourceGroupName = req.GetQueryNameValuePairs()
        .FirstOrDefault(q => string.Compare(q.Key, "resourcegroupname", true) == 0)
        .Value;

Now you can use the resourceGroupName variable inside of your code, or you can pass it forward to your webhook.

Have fun with ARM and Azure Functions!

1 thought on “Run Azure Functions from your Quickstart ARM Templates

  1. Thats a good idea. Thanks for sharing. I am going to try it to see if it works for my needs

    Liked by 1 person

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: