Terraform - Create a Storage Space and Modules

April 24, 2021

Following on from my introductory posts around Terraform, in this post, I’m going to create an Azure Storage account and blob container within Terraform. I’m then going to split the terraform file up so that it can be better managed.

For the purpose of continuity, let’s see what we already have in the file:



# Configure the Azure provider
terraform {
  required\_providers {
    azurerm = {
      source = "hashicorp/azurerm"
      version = ">= 2.26"
    }
  }
}
provider "azurerm" {
  features {}
}
resource "azurerm\_resource\_group" "rg" {
  name     = "myTFResourceGroup"
  location = "ukwest"
}

# App Service
resource "azurerm\_app\_service\_plan" "app-service-plan" {
  name                = "pcm-app-service-plan"
  location            = azurerm\_resource\_group.rg.location
  resource\_group\_name = azurerm\_resource\_group.rg.name
  sku {
    tier = "Standard"
    size = "S1"
  }
}
resource "azurerm\_app\_service" "app-service" {
  name                = "pcm-app-service"
  location            = azurerm\_resource\_group.rg.location
  resource\_group\_name = azurerm\_resource\_group.rg.name
  app\_service\_plan\_id = azurerm\_app\_service\_plan.app-service-plan.id
}

In this post, we’re going to create an Azure storage account and container. As before, I had a look here to determine what the resource type would be.

The script to add the new resource is quite straight-forward:



# Storage Account & Container
resource "azurerm\_storage\_account" "storageaccount1" {
  name                     = "pcmstorageaccount1"
  resource\_group\_name      = azurerm\_resource\_group.rg.name
  location                 = azurerm\_resource\_group.rg.location
  account\_tier             = "Standard"
  account\_replication\_type = "LRS"
}
resource "azurerm\_storage\_container" "blobcontainer" {
  name                  = "content"
  storage\_account\_name  = azurerm\_storage\_account.storageaccount1.name
  container\_access\_type = "private"
}


Let’s now see how we can separate our new block into a separate file.

Modules

What we can do with modules is to split off a portion of the terraform configuration into its own file. Let’s try creating a “create-storage.tf” file. Create it in a new directory (I’ll explain why shortly) called Modules:

The file itself basically contains the part of the main config that relates to storage:



variable "resource-name" {}
variable "resource-location" {}
variable "unique-name" {}
# Storage Account & Container
resource "azurerm\_storage\_account" "storageaccount1" {
  name                     = var.unique-name
  resource\_group\_name      = var.resource-name
  location                 = var.resource-location
  account\_tier             = "Standard"
  account\_replication\_type = "LRS"
}
resource "azurerm\_storage\_container" "blobcontainer" {
  name                  = "content"
  storage\_account\_name  = azurerm\_storage\_account.storageaccount1.name
  container\_access\_type = "private"
}

There’s two things of note here: firstly, we have some variables defined at the top, and secondly, we’re using them with the syntax: var.[name]:

We can then use that in the root module like this:



module "storage" {
  resource-name = azurerm\_resource\_group.rg.name
  resource-location = azurerm\_resource\_group.rg.location
  unique-name = "pcmstorageaccount2"
  source = ".\\\\modules"
}

Notice that we supply only two things to the module: the variables that we defined inside the module itself, and the source, which is simply a pointer for terraform to work out where the module is.

The next step is to re-init.

terraform init

terraform init amongst other things, scans the directory for references to modules; and, where it finds one, it loads it in. If you execute terraform plan without first init, then you’ll get the following error:

Error: Module not installed

on main.tf line 47: 47: module “storage” {

This module is not yet installed. Run “terraform init” to install all modules required by this configuration.

Caveat

I mentioned I would explain why we needed a Modules directory; it took be a few tries before it dawned on me. Terraform supports the following syntax:



module "storage" {
  resource-name = azurerm\_resource\_group.rg.name
  resource-location = azurerm\_resource\_group.rg.location
  unique-name = "pcmstorageaccount2"
  source = ".\\\\."
}

That is, you can reference the current directory as the location for the module. However, what Terraform actually does is to scan that directory for all modules - including the root module (in our case main.tf). Meaning that it will find that, scan the file, find a reference to a sub-module, scan the current directory, find the root module, find the reference to the sub-module, scan the current directory… you get the idea.

Output

Although we don’t need it for our case, terraform does support the concept of an output for a module. There’s a block type called output:



output "some-name" {
    value = resource.value
}

In the calling code, this would be referred to as module-name.some-name



Profile picture

A blog about one man's journey through code… and some pictures of the Peak District
Twitter

© Paul Michaels 2022