Project Bicep v0.2 for Azure Deployments
Tags: azure, devops, biceplang, iac
Published: 2020-11-14 12:23:09

If you have followed my last post [First look at Project Bicep, an Azure Resource Manager templates DSL]( https://dev.to/omiossec/first-look-at-project-bicep-an-azure-resource-manager-templates-dsl-4jif) you already know Project Bicep. 
Bicep is a Domain Specific Language for ARM Templates. The goal is to make ARM code easier to read and understand. Bicep files compile to ARM JSON format ready to deploy to Azure with your favorite tools, PowerShell or Azure CLI.
The v 0.2 release is available since 12 November and this version has several improvements.
 * Module support 
 * Validation of all Azure resource types
 * Target scope (Tenant, Management Group, Subscription and by default Resource Group)
 * A better VSCode experience 

For Visual Studio Code, there is an important change, the extension is available in the marketplace and not as VSIX file.
If you have installed the extension for VSCode for version 0.1.X you will need to remove the extension installed via VSIX. Go to your Visual Studio Code extension folder while VS Code isn't running and remove the extension's folder. The name should be "azure.vscode-bicep-0.1XXXX” 
On Windows, the VS Code extension folder is located in 
*%USERPROFILE%\.vscode\extensions*
On Mac OS and Linux 
*$HOME/.vscode/extensions*

You can restart VS Code. As the Bicep VSCode is now available on the marketplace, there will be no need to update the extension by removing the older one. Go to extension and simply search for bicep and install it.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/qznhfgzvhfrtpbzet8cn.png)

Now if you create a file, with the .bicep extension you will see the bicep language service at the bottom and the right of  Visual Studio Code windows.  

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/0wjkiwvysj08ykw9amk6.png)


You will also need to install the new version of Bicep. 
For Windows simply, download the new release from [Github]( https://github.com/Azure/bicep/releases/download/v0.2.3/bicep-setup-win-x64.exe) and execute the file to update your version. 

For macOS, you will need some extra steps. The first versions of Bicep didn't have a Brew formula, and the installation process was manual.
But now, with this new version, you can use Brew for the installation, but before you will need to uninstall the v 0.1 version.


```bash
rm '/usr/local/bin/bicep'

brew tap azure/bicep https://github.com/azure/bicep

brew install azure/bicep/bicep
```

Now we can use it and discover new features of this version. 


# VS Code integration

The language service in Visual Studio Code offers a better experience. When creating a resource you can have a complete list of Azure resources following by their API version. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/kjg9icy42lfb9cqe35yr.png)

You will also find a better syntax checker that will help you to find errors in your code.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/9bxmomols0pekuuey0l2.png)

# Modules

 bicep module is a bicep file that exposes parameters and deploys resources from another bicep file. Modules are like functions; you provide some parameters and the module creates resources and returns the output.
Modules enable you to modularize deployments by obfuscating some part of the code and by creating ready to use bicep files.
For example, you want your team to create their templates, but you want to be sure to use a virtual network with a network security group associated with a subnet. With modules, you can embed complexes configuration into a module, so your team focus on the main development.

Creating a module is simple, a module is a single bicep file with optional parameters and output.

```
// Param Section
param  vnetName string
param  vnetPrefix string
param vnetLocation string = resourceGroup().location

// VNET 
resource vnet 'Microsoft.Network/virtualNetworks@2020-06-01' = {
  name: vnetName
  location: vnetLocation
  properties: {
    addressSpace: {
      addressPrefixes: [
        vnetPrefix
      ]
    }
    subnets: [
      {
        name: 'defaultSubnemt'
        properties: {
          addressPrefix: vnetPrefix
          networkSecurityGroup: {
            id: subnetNSG.id
          }
        }
      }
    ]
  }
}

resource subnetNSG 'Microsoft.Network/networkSecurityGroups@2020-06-01' = {
  name: '${vnetName}-nsg'
  location: vnetLocation
  properties: {
    securityRules: [
      {
        name: 'allow-web'
        properties: {
          priority: 1000
          sourceAddressPrefix: '*'
          protocol: 'Tcp'
          destinationPortRange: '80'
          access: 'Allow'
          direction: 'Inbound'
          sourcePortRange: '*'
          destinationAddressPrefix: '*'
        }
      }
    ]
  }
}

output vnetID string = vnet.id
``` 

The output here is needed to reference the virtual network ID created by the module for later use. 

To use the module

``` 
module networkID './network.bicep' = {
  name: 'networkID'
  params: {
    vnetName: '${defaultVmName}-vnet'
    vnetPrefix: '10.0.0.0/24'
  }
}
``` 
The complete main.bicep file 

``` 
var defaultLocation = resourceGroup().location
var diskSku = 'Premium_LRS'
var defaultVmName = '${vmPrefix}-${environmentName}'
var defaultVmNicName = '${defaultVmName}-nic'

param vmOS string {
  default: '2019-Datacenter'
  allowed: [
      '2016-Datacenter'
      '2016-Datacenter-Server-Core'
      '2016-Datacenter-Server-Core-smalldisk'
      '2019-Datacenter'
      '2019-Datacenter-Server-Core'
      '2019-Datacenter-Server-Core-smalldisk'
    ] 
}
param localAdminPassword string {
  secure: true
  metadata: {
      description: 'password for the windows VM'
  }
}
param vmPrefix string {
  minLength: 1
  maxLength: 9
}
param environmentName string {
  allowed: [
    'prod'
    'dev'
  ]
}

module networkID './network.bicep' = {
  name: 'networkID'
  params: {
    vnetName: '${defaultVmName}-vnet'
    vnetPrefix: '10.0.0.0/24'
  }
}

resource vmNic 'Microsoft.Network/networkInterfaces@2017-06-01' = {
  name: defaultVmNicName
  location: defaultLocation
  properties: {
    ipConfigurations: [
      {
        name: 'ipconfig1'
        properties: {
          subnet: {
            id: '${networkID}/subnets/defaultSubnemt'
          }
          privateIPAllocationMethod: 'Dynamic'
        }
      }
    ]
  }
}

resource vmDataDisk 'Microsoft.Compute/disks@2019-07-01' = {
  name: '${defaultVmName}-vhd'
  location: defaultLocation
  sku: {
      name: diskSku
  }
  properties: {
      diskSizeGB: 32
      creationData: {
          createOption: 'Empty'
      }
  }

}

resource vm 'Microsoft.Compute/virtualMachines@2019-07-01' = {
  name: defaultVmName
  location: defaultLocation
  properties: {
    osProfile: {
      computerName: defaultVmName
      adminUsername: 'localadm'
      adminPassword: localAdminPassword
      windowsConfiguration: {
        provisionVMAgent: true
      }
    }
    hardwareProfile: {
      vmSize: 'Standard_F2s'
    }
    storageProfile: {
      imageReference: {
        publisher: 'MicrosoftWindowsServer'
        offer: 'WindowsServer'
        sku: vmOS
        version: 'latest'
      }
      osDisk: {
        createOption: 'FromImage'
      }
      dataDisks: [
        {
          name: '${defaultVmName}-vhd'
          createOption: 'Attach'
          caching: 'ReadOnly'
          lun: 0
          managedDisk: {
            id: vmDataDisk.id
          }
        }
      ]
    }
    networkProfile: {
      networkInterfaces: [
        {
          properties: {
            primary: true
          }
          id: vmNic.id
        }
      ]
    }
  }
}
``` 

The module is translated in JSON into a deployment resource, but the bicep part is easier to read and understand. 
Note you can also call a module inside another module.

Another feature is to be able to target scope to deployment resources in one of the four scopes. 
To create a bicep file targeting another scope than the resource group you will need to use the targetScope keyword. 

```
targetScope= 'subscription'

param rgName string

resource rg 'Microsoft.Resources/resourceGroups@2020-06-01' = {
  location: 'francecental'
  name: rgName

}
``` 

This bicep file creates a resource group in the subscription scope. It's also possible to use it in a module, as modules are translated into deployment resources in JSON. Deployment resources can deploy to any scope.
In this case, the module call need to include the scope keyword following by the desired scope 

``` 
module createRg './subscription.bicep' = {
  name: 'createRg'
    params: {
    rgName: 'myRG'
  }

  scope: scope.subscription()
}
``` 

With this version, Bicep is more and more complete. 
But it’s still in alpha version, and it’s not yet for production. There are still things missing that should be present in the next version.