I have been using Terraform over the last few months, having not used it in anger for quite a whileexternal link since the projects I have been working on have been more suitable for using Ansibleexternal link .

However, as I am doing more and more with Microsoft Azure, I found the Ansible modules a little lacking, plus for someone of the projects I have had to use an orchestration tool which can natively run on Windows.

Doing a little reading, I decided that I should be using modules so that i didn’t have to repeat lots of code. While this approach has mostly worked the current version of Terraform, 0.11.x, does have a few annoyances.

For example, in Azure, you have to create a resource group and then place resources you are launching in the group you have configured. Great I thought to myself I will just create a module which generates the resource group and then use an output to reference the resource group later in my plan.

The code for the module looked something like the following;

resource "azurerm_resource_group" "resource_group" {  name     = "${var.resource_group_name}"  location = "${var.location}"  tags     = "${var.tags}"}variable "name" {  description = "The name of the resource group we want to use"  default     = ""}variable "location" {  description = "The location/region where we are crrating the resource"  default     = ""}variable "tags" {  description = "The tags to associate the resource we are creating"  type        = "map"  default     = {}}output "rg_name" {  description = "The name of the newly created resource group"  value       = "${azurerm_resource_group.resource_group.name}"}

I was hoping that this meant that my main.tf could look like;

module "application-rg" {  source   = "modules/vnet"  name     = "${var.resource_group_name}"  location = "${var.location}"  tags     = "${merge(var.default_tags, map("type","resource"))}"}module "application-vnet" {  source              = "modules/vnet"  resource_group_name = "${module.application-rg.rg_name}"  location            = "${var.location}"  tags                = "${merge(var.default_tags, map("type","network"))}"  vnet_name           = "${module.application-rg.rg_name}-vnet"  address_space       = "10.10.0.0/16"}

While it worked, it did error a lot of the time from a standing start, this was because by Terraform was trying to create the vNet before the Resource Group had been created.

No problem I thought to myself — I remembered from the last time I used Terraform that there are resource dependencies in the form of . However, after much reading, I discovered that depends_on isn’t yet supported for modules — it is on the road map though.

Because of this I had to rejig my main.tf file to look like the following;

resource "azurerm_resource_group" "resource_group" {  name     = "${var.resource_group_name}"  location = "${var.location}"  tags     = "${merge(var.default_tags, map("type","resource"))}"}module "application-vnet" {  source              = "modules/vnet"  resource_group_name = "${azurerm_resource_group.resource_group.name}"  location            = "${var.location}"  tags                = "${merge(var.default_tags, map("type","network"))}"  vnet_name           = "${azurerm_resource_group.resource_group.name}-vnet"  address_space       = "10.10.0.0/16"}

This was not the end of the world, but as the documentation was pushing me down the module route, it was annoying.

The next lot of problem I had was with trying to use count with lists which had either been dynamically generated from another module or where hard coded. After much searching StackOverflowexternal link and GitHub issuesexternal link I found workarounds for most of my issues, such as the following (which has been abridged);

resource "azurerm_network_security_group" "nsg" {  resource_group_name = "${var.resource_group_name}"  location            = "${var.location}"  tags                = "${var.tags}"  name                = "${var.name}"}locals {  rules_locked_down_no = "${length(var.rules_locked_down)}"  rules_groups_no      = "${length(var.rules_groups)}"  rules_open_no        = "${length(var.rules_open)}"}resource "azurerm_network_security_rule" "rules_locked_down" {  count                       = "${local.rules_locked_down_no != 0 ? length(var.rules_locked_down) : 0}"  name                        = "${lookup(var.rules_locked_down[count.index], "name", "default_rule_name")}"  priority                    = "${lookup(var.rules_locked_down[count.index], "priority")}"  direction                   = "${lookup(var.rules_locked_down[count.index], "direction", "Any")}"  resource_group_name         = "${var.resource_group_name}"  network_security_group_name = "${azurerm_network_security_group.nsg.name}"}resource "azurerm_network_security_rule" "rules_open" {  count                       = "${local.rules_open_no != 0 ? length(var.rules_open) : 0}"  name                        = "${lookup(var.rules_open[count.index], "name", "default_rule_name")}"  priority                    = "${lookup(var.rules_open[count.index], "priority")}"  direction                   = "${lookup(var.rules_open[count.index], "direction", "Any")}"  resource_group_name         = "${var.resource_group_name}"  network_security_group_name = "${azurerm_network_security_group.nsg.name}"}resource "azurerm_network_security_rule" "rules_groups" {  count                                 = "${local.rules_groups_no != 0 ? length(var.rules_groups) : 0}"  name                                  = "${lookup(var.rules_groups[count.index], "name", "default_rule_name")}"  priority                              = "${lookup(var.rules_groups[count.index], "priority")}"  direction                             = "${lookup(var.rules_groups[count.index], "direction", "Any")}"  access                                = "${lookup(var.rules_groups[count.index], "access", "Allow")}"  resource_group_name                   = "${var.resource_group_name}"  network_security_group_name           = "${azurerm_network_security_group.nsg.name}"}

Here I had to use the locals to count the number of items in the list I was passing through so that it could be then be used by count.

This is something I would have expected to have worked when I first wrote the module as the syntax made sense, however, when I ran the original code this was pretty much the face I pulled when all I got was a message saying that the “count cannot be computed.”;

See this GitHub issue for more detailexternal link on why it didn’t work and what changes have been made in Terraform to fix it.

Most of the problems I came across while I have been revisiting Terraform appear to be either being fixed or having the ground-work laid for a fix in Terraform 0.12 which should be released very soon.

Until it is, I will be waiting — thinking about all of the work arounds I will have to undo.

For more information on Terraform 0.12 the following video is a good place to start;

Or the following blog posts from Hashicorp which go to make up a preview of Terraform 0.12external link ;

Update 16/02/2019


it is an interesting insight into what is going to behind the scenes to get this release out of the gate.