Azure

Revamping Shared Code with Azure Bicep User Defined Functions

Welcome to this article, where we will delve into creating clean and reusable code in Azure Bicep.

Overview

Discover how to simplify deploying your cloud resources on Microsoft Azure using Bicep’s new feature, “User Defined Functions,” currently in preview. This blog will guide you on writing code that can be recycled multiple times, aiding in better organization and management of your projects.

Whether you are new to Bicep or already have experience with it, this guide will demonstrate the effective use of functions for improved Azure deployments.

Pre-requisites

Since Bicep – User Defined Functions is currently in preview, please enable it in the Bicep Config of your root folder. You can do this by clicking on the View Command Palette as illustrated below.

Command Palette

This will open a popup where you can select Bicep: Create Bicep Configuration File as shown in the image below.

Create Bicep Configuration

By following these steps, a bicepconfig.json file will be created. You can replace the existing content with the provided JSON content.

{
  "experimentalFeaturesEnabled": {
    "userDefinedFunctions": true
  }
}

Note: If you prefer not to delete the existing content, you can simply add lines 2-4 from the code above to the bicepconfig.json file.

Before we begin creating Bicep – User Defined Functions, let’s consider a scenario where duplicate code may exist in various locations.

Real-World Scenario

Imagine you need to create a Storage account with different replication strategies based on the environment.

For non-production environments, you might choose Locally Redundant Storage (LRS) for cost-efficiency, while for production environments, Geo-Redundant Storage (GRS) might be preferred for increased resilience.

It’s important to note that multiple storage accounts may need to be created based on specific requirements.

Author Bicep Code

Let’s craft the following Bicep code that takes Storage Replication Type as a parameter.

storage.bicep

param pStorageAccountName string

param pLocation string = resourceGroup().location

param pStorageSKU string

resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = {
  name: pStorageAccountName
  location: pLocation
  sku: {
    name: pStorageSKU
  }
  kind: 'StorageV2'
}

main.bicep

param pEnv string

param pLogicAppStorageAccountName string

param pFunctionAppStorageAccountName string

param pLocation string = resourceGroup().location

module fappStorage 'modules/storage.bicep' = {
  name: 'fappStorage'
  params: {
    pStorageAccountName: pFunctionAppStorageAccountName
    pLocation: pLocation
    pStorageSKU: pEnv == 'prd' ? 'Standard_GRS' : 'Standard_LRS'
  }
}

module lappStorage 'modules/storage.bicep' = {
  name: 'lappStorage'
  params: {
    pStorageAccountName: pLogicAppStorageAccountName
    pLocation: pLocation
    pStorageSKU: pEnv == 'prd' ? 'Standard_GRS' : 'Standard_LRS'
  }
}

In the provided code snippet, a logical condition is set to determine the environment classification as ‘PRD’. Based on this classification, the pStorageSKU parameter is assigned either ‘Standard_GRS’ or ‘Standard_LRS’ accordingly.

The repetitive logical code in the condition can be optimized. Let’s utilize Bicep User Defined Functions to refactor and create more concise and cleaner code.

User Defined Function

Let’s introduce a new Bicep User Defined Function as outlined below.

func GetStorageAccountKind(Env string) string => Env=='prd' ? 'Standard_GRS' : 'Standard_LRS'

module fappStorage 'modules/storage.bicep' = {
  name: 'fappStorage'
  params: {
    pStorageAccountName: pFunctionAppStorageAccountName
    pLocation: pLocation
    pStorageSKU: GetStorageAccountKind(pEnv)
  }
}

module lappStorage 'modules/storage.bicep' = {
  name: 'lappStorage'
  params: {
    pStorageAccountName: pLogicAppStorageAccountName
    pLocation: pLocation
    pStorageSKU: GetStorageAccountKind(pEnv)
  }
}

As seen in the code snippet above, the logical condition is now streamlined in the Bicep User-Defined Function called GetStorageAccountKind. This function is then invoked instead of the previous logical condition.

Any future changes to the logic will only require modification in one place, making the code clean and concise.

While the GetStorageAccountKind function is currently confined to the current bicep file, you can expand its usability to other bicep files by creating a Bicep Module for the User Defined Function. Let’s create a new module named udf.bicep as illustrated below.

Udf.bicep

param pEnv string

func GetStorageAccountKind(Env string) string => Env=='prd' ? 'Standard_GRS' : 'Standard_LRS'

output StorageAccountKind string = GetStorageAccountKind(pEnv)

It’s important to note that StorageAccountKind is set as an output parameter.

Now, we need to call the UDF.bicep module from the main.bicep file.

main.bicep

param pEnv string

param pLogicAppStorageAccountName string

param pFunctionAppStorageAccountName string

param pLocation string = resourceGroup().location

module udf 'modules/udf.bicep' = {
  name: 'udf'
  params: {
    pEnv: pEnv
  }
}

module fappStorage 'modules/storage.bicep' = {
  name: 'fappStorage'
  params: {
    pStorageAccountName: pFunctionAppStorageAccountName
    pLocation: pLocation
    pStorageSKU: udf.outputs.StorageAccountKind
  }
}

module lappStorage 'modules/storage.bicep' = {
  name: 'lappStorage'
  params: {
    pStorageAccountName: pLogicAppStorageAccountName
    pLocation: pLocation
    pStorageSKU: udf.outputs.StorageAccountKind
  }
}

Summary

This article introduces the concept of User Defined Functions (UDFs) in Bicep, highlighting how they can enhance code reusability, readability, and maintainability in infrastructure deployment tasks. By providing practical examples and insights, readers can learn how to leverage UDFs to modularize their Bicep code and streamline Azure deployments effectively.

Whether you’re a novice or an experienced developer, this guide empowers you with the necessary knowledge to maximize the potential of Bicep functions for seamless and scalable Azure deployments.

To explore more about Skrots, our services, and blogs, visit Skrots. Discover the range of services we offer at Skrots Services.

Show More

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button