A couple of weeks ago I posted an article on my first experiences with Project ‘Bicep’. Back then, Project ‘Bicep’ was just released as an 0.1 Alpha version. In case you missed that article, follow this link.
Recently, version 0.2 was released which contains some great features as listed on the left. I was especially looking forward to the option of using Modules and Scopes and having IntelliSense and code formatting to improve the overall authoring experience.
To get started, install the latest Bicep 0.2 release using the URL below.
To use bicep VS Code extension, simply install the latest extension from within VSCode. If you were using a previous version of the Code Extension you have to uninstall that version first.
We are now ready to start testing some of the new features in this 0.2 release. First of all, modules! Modules can be used to separate Bicep code, that creates a specific (set of) resources, into different files. Not only does this allow you to further simplify a single bicep file into multiple files, it also allows you to reuse code by simply calling the modules.
Creating a new bicep module is no different than creating a regular bicep file. Modules also have the .bicep extension and the same way of declaring parameters, variables and resources.
Let’s start by creating a super simple module that deploys a new Vnet and Subnet. Below is the Bicep code. If you have played with Bicep 0.1 before you’ll notice that this is no different than creating a regular bicep file. I still love how extremely simply the Bicep syntax is!
Before we start: Yes, the code snippets throughout this article are screenshots and therefor not easy to copy-paste and reuse, but I shared the entire set of all Bicep files, Bicep Modules and transpiled JSON code on Github here: Multi-module Bicep project for WVD. I’m using screenshots as this allows for easy reading and annotations.
Before Bicep 0.2 release we would build (transpile) a corresponding JSON file from the Bicep file by running the command below.
And since a Bicep Module file is no different than a regular Bicep file, we still can. We are however not going to do that. Instead we are going to call the module from another Bicep file. To call a Bicep module we use the code below. We specify the keyword ‘Module’ followed an identifier and then specifying the ‘type’ which in this case is the location of the bicep file, in this case the module that creates the Vnet and Subnet. Note that we can pass parameters to overwrite any defaults specified in the module itself. Also, the ‘name’ that we specify here is not the name of the vnet, but it is the name of the nested deployment that gets created in JSON, more on that later.
Second thing you’ll notice that we specified a scope. This is great because it allows us to specify the, in this case, resourceGroup where the resources of this module are going to be deployed. So this also allows us to call several different modules that deploy different resources into various different resource groups. This comes in very handy for larger deployments that expand a single resource group. Do make sure that you specify targetScope as ‘subscription’ inside the Bicep file from where you call your Modules.
We are now only calling a single Bicep module from another Bicep file. That of course does not really add value. Let’s step up our game and create another module. This time a module that creates a Storage Account including a file share.
Let’s start with the Storage Account and deliberately leave out a property inside resource declaration that defined the storage account. Note that the VSCode with the extension notifies us of the exact parameter that is missing. Great authoring experience! Not only when mistakenly leaving out a parameter, but throughout the creation of the resource, intellisense provides great feedback in properties to create.
Let’s now add the creation of a basic file share inside this module. Note that VSCode with the Bicep Extension allows us to easily browse through all resources including in this case all available api versions of the storage account resource.
Let’s now move forward to the test case of this blog post, creating a multi-module Bicep Project that deploys the following for us: a WVD Environment containing the following:
- 4 new Resource Groups
- Vnet and Subnet
- Storage account including a File Share
- Log Analytics Workspace
- Windows Virtual Desktop Hostpool, AppGroup and Workspace
- Configuring the diagnostic information for all WVD Backplacne components
Let’s start by creating the main bicep file from where we will be calling the various Bicep Modules. We start by defining the parameters. Since we will be calling various Bicep Modules from within the main file, we define the parameters we need for all modules. Again, we also set the targetScope to ‘Subscription’ to allow us to create Azure objects into various different Resource Groups.
Next, we create 4 new Resource Groups and we generate the names based on the a defined prefix. We could of course also have created these 4 Resource Groups using a module, but I chose not to do so in order to show that you can combine the creation of resources with calling modules from a single main bicep file.
Let’s now call our first module. This module will create a WVD Hostpool, AppGroup and Workspace, create relationships between all objects and also configure the diagnostic information for all of the WVD objects.
In a previous article I already focussed on the creation of the WVD Objects itself, so I will not repeat that here. In order to create the Diagnostic information for the WVD Objects, obviously the WVD Objects themselves need to be created first. And the Log Analytics Workspace needs to exist too. To achieve this, I’m actually calling another module from within this module 🙂
Note that for the parameter logAnalyticsWorkspaceID, I’m referring to the ID of the log analytics workspace. This causes Bicep to auto-create the necessary dependency in JSON.
In fact, Bicep took care of a lot more depends on sections for us throughout the generated JSON file, we call this implicit dependencies. When authoring JSON directly, these would all have to be explicitly created.
To finish off the main bicep file we call the 2 other modules that create the network and file services components respectively.
The end result is a main bicep file with 5 Bicep module files as shown below.
When Bicep modules are transpiled into ARM template JSON, they are turned into a nested inline deployment automatically. Basically, each module equals one nested deployment regardless of the number of resources that are defined inside a single module. This means we only have to transpile the main bicep file. The build process, which only takes a second to complete, transpiles all bicep files automatically including all the module files that are used. Below is the build command I used. I did get a warning. This is a know issue with version 0.2 because extension resources like e.g. diagnosticsettings and locks are not detected in this release yet. This functionality is going to be added soon. For now we can safely ignore the warning, and the JSON is successfully created.
From within VSCode we can directly deploy the generated JSON file to Azure Resource Manager.
And here is the end result in Azure, we have 4 new Resource Groups created.
A WVD Hostpool, AppGroup and Workspace are created and the objects are connected to each other.
A Storage account with a File Share is created.
A Log Analytics Workspace is created including the diagnostic configuration of all WVD Objects.
And lastly, a Virtual Network with a Subnet is created.
This concludes my first test drive with Bicep 0.2. I must say impressed by the added features and can’t wait for new features to be added in the already planned 0.3 release!
As mentioned before, I made the Bicep files including all the Bicep modules and the transiled JSON code available on GitHub. Feel free to reuse and contribute!