Showing posts with label function. Show all posts
Showing posts with label function. Show all posts

Simplify your deployment with nested Azure Resource Manager (ARM) templates


Most solutions, if not all, are composed of multiple parts: backend, frontend, services, APIs, etc. Because all parts could have a different life-cycle it's important to be able to deploy them individually. However, sometimes we would like to deploy everything at once. It's exactly the scenario I had in a project I'm working on where with backend and one frontend.

In this post, I will explain how I use nested Azure Resource Manager (ARM) templates and conditions to let the user decide if he wants to deploy only the backend or the backend with a frontend of his choice. All the code will be available in GitHub and if you prefer, a video version is available below.
(This post is also available in French)

The Context


The project used in this post my open-source budget-friendly Azure URL Shortener. Like mentioned previously the project is composed of two parts. The backend leverage Microsoft serverless Azure Functions, it a perfect match in this case because it will only run when someone clicks a link. The second part is a frontend, and it's totally optional. Because the Azure Functions are HTTP triggers they act as an API, therefore, they can be called from anything able to do an HTTP call. Both are very easily deployable using an ARM template by a PowerShell or CLI command or by a one-click button directly from GitHub.

The Goal


At the end of this post, we will be able from one-click to deploy just the Azure Functions or to deploy them with a frontend of our choice (I only have one right now, but more will come). To do this, we will modify the "backend" ARM template using condition and nest the ARM template responsible for the frontend deployment.

The ARM templates are available here in there [initial](https://github.com/FBoucher/AzUrlShortener/tree/master/tutorials/optional-arm/before) and [final](https://github.com/FBoucher/AzUrlShortener/tree/master/tutorials/optional-arm/before/after) versions.

Adding New Inputs


We will nest the ARM templates, this means that our backend template (azureDeploy.json) will call the frontend template (adminBlazorWebsite-deployAzure.json). Therefore we need to add all the required information to azureDeploy.json to make sure it's able to deploy adminBlazorWebsite-deployAzure.json successfully. Looking at the parameter required for the second template, we only two need values AdminEMail and AdminPassword. All the other can be generated or we already have them.

We will need also another parameter the will act as our selection option. So let's add a parameter named frontend and allowed only two values: none and adminBlazorWebsite. If the value is none we only deploy the Azure Function. When the value is adminBlazorWebsite we will deploy the Azure Function, of course, but we will also deploy an admin website to go with it.

Following the best practices, we add clear detail and add those three parameters in the parameters section of the ARM template

"frontend": {
    "type": "string",
    "allowedValues": [
        "none",
        "adminBlazorWebsite"
    ],
    "defaultValue": "adminBlazorWebsite",
    "metadata": {
        "description": "Select the frontend that will be deploy. Select 'none', if you don't want any. Frontend available: adminBlazorWebsite, none. "
    }
},
"frontend-AdminEMail": {
    "type": "string",
    "defaultValue": "",
    "metadata": {
        "description": "(Required only if frontend = adminBlazorWebsite) The EMail use to connect into the admin Blazor Website."
    }
},
"frontend-AdminPassword": {
    "type": "securestring",
    "defaultValue": "",
    "metadata": {
        "description": "(Required only if frontend = adminBlazorWebsite) Password use to connect into the admin Blazor Website."
    }
}

Nested Templates


Let's assume for now that we always deploy the website when we deploy the Azure Function, to keep things simple. What we need now is to used nested ARM template, and that when you deploy an ARM template from inside another ARM template. This is done with a Microsoft.Resources/deployments node. Let's look at the code:

{
    "name": "FrontendDeployment",
    "type": "Microsoft.Resources/deployments",
    "dependsOn": [
        "[resourceId('Microsoft.Web/sites/', variables('funcAppName'))]",
        "[resourceId('Microsoft.Web/sites/sourcecontrols', variables('funcAppName'), 'web')]"
    ],
    "resourceGroup": "[resourceGroup().name]",
    "apiVersion": "2019-10-01",
    "properties": {
        "mode": "Incremental",
        "templateLink": {
            "uri": "[variables('frontendInfo')[parameters('frontend')].armTemplateUrl]"
        },
        "parameters": {
            "basename": {
                "value" : "[concat('adm', parameters('baseName'))]"
            },
            "AdminEMail": {
                "value" : "[parameters('frontend-AdminEMail')]"
            },
            "AdminPassword": {
                "value" : "[parameters('frontend-AdminPassword')]"
            },
            "AzureFunctionUrlListUrl": {
                "value" : "[concat('https://', reference(resourceId('Microsoft.Web/sites/', variables('funcAppName')), '2018-02-01').hostNames[0], '/api/UrlList?code=', listkeys(concat(resourceId('Microsoft.Web/sites/', variables('funcAppName')), '/host/default/'),'2016-08-01').functionKeys.default)]"
            },
            "AzureFunctionUrlShortenerUrl": {
                "value" : "[concat('https://', reference(resourceId('Microsoft.Web/sites/', variables('funcAppName')), '2018-02-01').hostNames[0], '/api/UrlShortener?code=', listkeys(concat(resourceId('Microsoft.Web/sites/', variables('funcAppName')), '/host/default/'),'2016-08-01').functionKeys.default)]"
            },
            "GitHubURL": {
                "value" : "[parameters('GitHubURL')]"
            },
            "GitHubBranch": {
                "value" : "[parameters('GitHubBranch')]"
            },
            "ExpireOn": {
                "value" : "[parameters('ExpireOn')]"
            },
            "OwnerName": {
                "value" : "[parameters('OwnerName')]"
            }

        }
    }
}

If we examine this node, we have the classic: name, type, dependsOn, resourceGroup, apiVersion. Here We really want the Azure Functions to be fully deployed so we need the FunctionApp to be created AND the GitHub sync to be complete, this is why there is also a dependency on Microsoft.Web/sites/sourcecontrols.

In properties we will pass the mode as Incremental as it will leave unchanged resources that exist in the resource group but aren't specified in the template.

Learn more about the Azure Resource Manager deployment modes here as they are very powerful.

The second property is templateLink. This is really important as it's the URL to the other ARM template. That URI must not be a local file or a file that is only available on your local network. You must provide a URI value that downloadable as HTTP or HTTPS. In this case, it's a variable that contains the GitHub URL where the template is available.

Finally, we have the parameters, and this is how we pass the values to the second template. Let's skip those where I just pass the parameter value from the caller to the called, and focus on basename, AzureFunctionUrlListUrl, and AzureFunctionUrlShortenerUrl.

For basename I just add a prefix to the parameter basename received, this way the resource names will be different but we can still see the "connection". That's purely optional, you could have added this value in a parameter to azureDeploy.json, I prefer keeping the parameters a minimum as possible as I think it simplifies the deployment for the users.

Finally for AzureFunctionUrlListUrl, and AzureFunctionUrlShortenerUrl I needed to retrieve the URL of the Azure Function with the security token because they are secured. I do that by concatenating different parts.

Component Value
Beginning of the URL 'https://'
Reference the Function App, return the value of hostname reference(resourceId('Microsoft.Web/sites/', variables('funcAppName')), '2018-02-01').hostNames[0]
Specify the Function targeted in this case UrlList. And starting the querystring to pass the code (aka. security token) '/api/UrlList?code='
Using the new listkeys function to retrieve the default Function key. listkeys(concat(resourceId('Microsoft.Web/sites/', variables('funcAppName')), '/host/default/'),'2016-08-01').functionKeys.default

Conditional parts


Now that the second ARM template can be deployed, let's add a condition so it gets, indeed, deploy only when we desire. To do this it's very simple, we need to add a property condition.

{
    "name": "FrontendDeployment",
    "type": "Microsoft.Resources/deployments",
    "condition": "[not(equals(parameters('frontend'), 'none'))]",
    "dependsOn": [
        "[resourceId('Microsoft.Web/sites/', variables('funcAppName'))]",
        "[resourceId('Microsoft.Web/sites/sourcecontrols', variables('funcAppName'), 'web')]"
    ]
}

In this case, is the value of the parameter is different then none, the nested template will be deployed. When a condition end-up being "false", the entire resource will be ignored during the deployment. How simple or complex are your conditions... that's your choice!

Happy deployment. :)




Reading Notes #423

Every Monday, I share my "reading notes". Those are the articles, blog posts, podcast episodes, and books that catch my interest during the week and that I found interesting.

It's a mix of the actuality and what I consumed. You think you may have an interesting post, share it!
My office is in the basement... so I didn't conplained.

Cloud

Programming

Podcasts

Miscellaneous


~

Reading Notes #422


Cloud

Programming

Podcasts

Miscellaneous

~


Reading Notes #415


Every Monday, I share my "reading notes". Those are the articles, blog posts, podcast episodes, and books that catch my interest during the week and that I found interesting. It's a mix of the actuality and what I consumed.



Cloud

Programming

Miscellaneous

  • What are Azure CLI Extensions? (Michael Crump) - An interesting first article of a series. This one introduces us to the extension... Hmmm. I think I have an idea.
~


Reading Notes #412




Every Monday, I share my reading notes. Those are the articles, blog posts, podcast episodes, and books that catch my interest during the week and that I found interesting. It's a mix of the actuality and what I consumed.


Cloud

Programming

Podcasts

  • #25: Shayne Boyer - Social Coder (The Solo Coder Podcast) - Once again a very nice episode. It was wonderful to discover my colleague to this interview. Well done.

Miscellaneous





Reading Notes #407


Every Monday, I share my reading notes. Those are the articles, blog posts, podcast episodes, and books that catch my interest during the week and that I found interesting. It's a mix of the actuality and what I consumed.

Cloud

  • Generating Images with Azure Functions (Aaron Powell) - Brilliant usage of Azure function and its the first one I see in F#! All the code is available in GitHub, definitely worth the detour.

Programming

  • Use MongoDB in Your C# ASP.NET Apps (Terje Kolderup) - This is a very complete tutorial the shows all the code and explains step by step how to add, configure and use MongoDB.

Podcasts


Miscellaneous

  • Is that position available for remote? (Mark Downie) - A very interesting post that, I think, explains well the 'behind the scene' of the response we can get when asking the remote question.
~

Reading Notes #403



Every week, I publish my reading notes. Those are the articles, blog posts, podcast episodes, and books that catch my interest and that I found interesting. It's a mix of the actuality and what I was looking for.

I passed the 4k subscribers mark on YouTube

The suggestion of the week


Cloud


Programming

  • ASP.NET Core updates in .NET Core 3.1 (Sourabh Shirhatti) - I'm very excited about this 3.1 version.I'm not sure why maybe it's because it is the long-time support (LTS). Nevertheless, I will update all my projects.

Miscellaneous

  • 7 Dangers of Micromanagement ( Jack Wallen) - Nice post to help you give the best version of yourself. (Note it's now 6, but it was 7 when I read it)

Books


Build Your Dream Stream

Ashley

Great book with many very interesting ideas.Not the same things that we ear elsewhere, or if it is, it's in very different words.








~

Reading Notes #402

Every week, I publish my reading notes. Those are the articles, blog posts, podcast episodes, and books that catch my interest and that I found interesting. It's a mix of the actuality and what I was looking for.

Cloud

Programming

Miscellaneous

Books

The Art of Thinking Clearly

by Rolf Dobelli

I'm still balanced about this book. It was a good book, even if I found some chapters that were too long. I also got lost by moments. I had the impression that some thoughts or ideas were not developed correctly and more quickly wrapped. In counterpart, some were very well served and clear.

Reading Notes #398


Cloud


Programming


Miscellaneous



Books


10-Minute Focus: 25 Habits for Mastering Your Concentration and Eliminating Distractions 

(Daniel Walter)

Nothing new here but it's clear and very well explained. Honestly it good to revisit those productivity/ focus habits... It helps to stay on our toes...

Reading Notes #396

Suggestion of the week

Programming

Miscellaneous

~


Reading Notes #393


Suggestion of the week

  • GitHub stars won’t pay your rent (Kitze) - What a great story! This is an awesome journey of a developers who worked hard, took some risk and... Got result. All developer should read this.

Cloud

Programming

Miscellaneous

Reading Notes #391


Suggestion of the week

  • How to Use Github Professionally (Aaron Stannard) - This post is great! Tons of information and best practices (with an explanation of why its a best practice).

Cloud


Programming


Books

Living with the Monks: What Turning Off My Phone Taught Me about Happiness, Gratitude, and Focus 

Author: Jesse Itzler

I really enjoyed this book. Yes it's light and funny, but don't get fool, there is a deeper message here. I think Jessy wins his challenge by going into a monastery so we don't have to. We all have what it takes to live a more purposeful life, we just need to pause. Showdown, to go faster, do less to do more... Embrace the silence.



~

Reading Notes #386

Cloud


Programming


Databases


Miscellaneous


~


The Dog-Not-a-Dog Workshop


I recently presented, a workshop at the TOHack to get started with Azure. The goal was to try different Azure services, and see how we could augment an existing website using serverless function and artificial intelligence.
(Aussi disponible en français)


During this workshop, a website is deployed automatically from GitHub. Then by adding an Azure Function and using the Vision API of Azure Cognitive Services, the final solution is able to detect when uploaded pictures are or not dogs and keep our image folder "clean". We call that application: The automatic Not a Dog application.

The step by step instruction with the code can be found on GitHub - Not-a-Dog-Workshop. The workshop can be done in about 45-60 minutes.

I also did a video that is available on my YouTube channel:



You have questions, you are blocked, it will be a pleasure to help you.


Reading Notes #383

Cloud


Programming


Miscellaneous


~

Reading Notes #382

Cloud


Programming

~

Reading Notes #379


Cloud

Programming

~

Reading Notes #378



Cloud

Programming

Miscellaneous

Reading Notes #375

Cloud

Programming

Podcast

  • Anthos Migrate, with Issy Ben-Shaul (Kubernetes Podcast from Google) - Nice update. I like the talk about Anthos it look like a great migration tool. I need to find that GitHub repo...

Reading Notes #373

Cloud


Programming


Books



Donald Miller

A really interesting book that helps to focus and keep in mind the most important. I didn't read it with a purpose of business really, but it did make me remember past experiences and it was easy to make the relationship between success and when the story was clear. Take the time to read it, do the exercises/ reflections required... it's worth it.










~