Learning Terraform Series
01. Deploying WVD
02. Remote State
03. WVD-as-a-Module [This Post]
In this third post in my Learning Terraform series I’ll explore the concept of Modules.
What is a Module?
“With Terraform, you can put your code inside of a Terraform module and reuse that module in multiple places throughout your code. Instead of having the same code copy/pasted in the staging and production environments, you’ll be able to have both environments reuse code from the same module.
This is a big deal. Modules are the key ingredient to writing reusable, maintainable, and testable Terraform code. Once you start using them, there’s no going back. You’ll start building everything as a module, creating a library of modules to share within your company, start leveraging modules you find online, and start thinking of your entire infrastructure as a collection of reusable modules.”
Source: https://blog.gruntwork.io/how-to-create-reusable-infrastructure-with-terraform-modules-25526d65f73d
Learning about Modules has completely changed how I approach Terraform, now rather than thinking of every Terraform file as a standalone entity I’m instead looking at what common elements I can make into a module.
I’ve used Windows Virtual Desktop (WVD) as a common theme for learning Terraform in my previous posts, and this fits extremely well into the model of a Module as the architecture of WVD is static, that is to say, the relationship between a Workspace, Application Group and Host Pool doesn’t change.
The Anatomy of a Module
The beauty of a Module is in its simplicity.
In short, any Terraform file is pretty much a module by default.
There is no discernible difference between the syntax and structure of a standard configuration file and that of a module other than when calling a module you pass in all unique resource values from the main configuration file rather than a variables file.
I’ve tried to show this in the figure below, in a standard Terraform configuration you would create a folder for your code and within it store the main and variable files. The main.tf file contain the Terraform provider (Azure, AWS etc) and the resources to create, you could pass in values from a variables.tf file in the same folder.

When calling or referencing a module however you would specify the variable values within the main configuration file, shown below in blue.
The module would commonly reside in its own folder structure, a central module library perhaps, the structure of which is identical to a standard Terraform configuration.
The biggest notable difference, and this will become evident in the code, is that modules’ variable file (shown in green) doesn’t contain any default values as those are passed in from outside.

WVD-as-a-Module
Building on from the code in my previous posts I’ve now converted the code to deploy WVD into a reusable module.

This code is available from my GitHub repo, here
Firstly, the below code is the main.tf that will call the module, in figure 2 above this is the script in blue.
# Get AzureRM Terraforn Provider
provider "azurerm" {
version = "2.31.1" #Required for WVD
features {}
}
# Remote State, replace with your resource group, storage account and container name
terraform {
backend "azurerm" {
storage_account_name = "vfftfstateusw2"
container_name = "tfstate"
key = "terraform.tfstate"
resource_group_name = "VFF-USE-RG-WVD-REMOTE"
}
}
# Create resource group
resource "azurerm_resource_group" "default" {
name = "VFF-USW-RG-WVD-FromMod"
location = "West US 2"
}
# Call WVD-as-a-Module and pass in variables
module "WVD-as-a-Module" {
source = "../Modules/WVD-as-a-Module"
rgname = azurerm_resource_group.default.name
region = azurerm_resource_group.default.location
pooledhpname = "VFF-WUS-TFRM-Mod"
pooledhpfriendlyname = "VFF Pooled Host Pool"
pooledhpdescription = "VFF Pooled Host Pool"
pooledhpremoteappname = "VFF-WUS-TFRM-Mod-RA"
pooledhpremoteappfriendlyname = "VFF Pooled Host Pool Remote Apps"
pooledhpremoteappdescription = "VFF Pooled Host Pool Remote Apps"
pooledhpdesktopappname = "VFF-WUS-TFRM-Mod-DT"
pooledhpdesktopappfriendlyname = "VFF Pooled Host Pool Remote Apps"
pooledhpdesktopappdescription = "VFF Pooled Host Pool Remote Apps"
workspace = "VFF-Terraform-Wkspc-Mod"
workspacefriendlyname = "VFF-Terraform-Workspace"
workspacedesc = "VFF-Terraform-Workspace"
pooledhpmaxsessions = 50
}
This next code is the WVD-as-a-Module main configuration File, in figure 2 this is show in orange.
Note, I recommend create a new folder structure for your modules.
terraform {
required_version = ">=0.12"
}
# Create "Pooled" WVD Host Pool
resource "azurerm_virtual_desktop_host_pool" "pooleddepthfirst" {
location = var.region
resource_group_name = var.rgname
name = var.pooledhpname
friendly_name = var.pooledhpfriendlyname
description = var.pooledhpdescription
type = "Pooled"
maximum_sessions_allowed = var.pooledhpmaxsessions
load_balancer_type = "DepthFirst"
}
#Create RemoteApp Application Group
resource "azurerm_virtual_desktop_application_group" "pooledremoteapp" {
name = var.pooledhpremoteappname
location = var.region
resource_group_name = var.rgname
type = "RemoteApp"
host_pool_id = azurerm_virtual_desktop_host_pool.pooleddepthfirst.id
friendly_name = var.pooledhpremoteappfriendlyname
description = var.pooledhpremoteappdescription
}
#Create Desktop Application Group
resource "azurerm_virtual_desktop_application_group" "pooleddesktopapp" {
name = var.pooledhpdesktopappname
location = var.region
resource_group_name = var.rgname
type = "Desktop"
host_pool_id = azurerm_virtual_desktop_host_pool.pooleddepthfirst.id
friendly_name = var.pooledhpdesktopappfriendlyname
description = var.pooledhpdesktopappdescription
}
# Create Workspace
resource "azurerm_virtual_desktop_workspace" "workspace" {
name = var.workspace
location = var.region
resource_group_name = var.rgname
friendly_name = var.workspacefriendlyname
description = var.workspacedesc
}
# Associate RemoteApp Application Group with Workspace
resource "azurerm_virtual_desktop_workspace_application_group_association" "workspaceremoteapp" {
workspace_id = azurerm_virtual_desktop_workspace.workspace.id
application_group_id = azurerm_virtual_desktop_application_group.pooledremoteapp.id
}
# Associate Desktop Application Group with Workspace
resource "azurerm_virtual_desktop_workspace_application_group_association" "workspacedesktop" {
workspace_id = azurerm_virtual_desktop_workspace.workspace.id
application_group_id = azurerm_virtual_desktop_application_group.pooleddesktopapp.id
}
Lastly, this is the associated variables file for the module, this is shown in green in figure 2.
variable "rgname" {
description = "Resource Group Name"
type = string
}
variable "region" {
description = "Region"
type = string
}
variable "pooledhpname" {
description = "Pooled Host Pool Name"
type = string
}
variable "pooledhpmaxsessions" {
description = "Max sessions per pooled host"
type = number
}
variable "pooledhpfriendlyname" {
description = "Pooled Host Pool Friendly Name"
type = string
}
variable "pooledhpdescription" {
description = "Pooled Host Pool Description"
type = string
}
variable "pooledhpremoteappname" {
description = "Pooled Host Pool RemoteApp App Group Name"
type = string
}
variable "pooledhpremoteappfriendlyname" {
description = "Pooled Host Pool RemoteApp App Group Friendly Name"
type = string
}
variable "pooledhpremoteappdescription" {
description = "Pooled Host Pool RemoteApp App Group Description"
type = string
}
variable "pooledhpdesktopappname" {
description = "Pooled Host Pool Desktop App Group Friendly Name"
type = string
}
variable "pooledhpdesktopappfriendlyname" {
description = "Pooled Host Pool Desktop App Group Friendly Name"
type = string
}
variable "pooledhpdesktopappdescription" {
description = "Pooled Host Pool Desktop App Group Description"
type = string
}
variable "workspace" {
description = "WVD Workspace Name"
type = string
}
variable "workspacefriendlyname" {
description = "WVD Workspace Friendly Name"
type = string
}
variable "workspacedesc" {
description = "WVD Workspace Description"
type = string
}

This code is available from my GitHub repo, here
If you have any questions or queries please get in touch on Twitter
Thanks.
4 thoughts on “Learning Terraform > WVD-as-a-Module”