Skip to content

Terraform Input Variables with Collection Type set

Step-01: Introduction

  • Implement Collection Type set
  • What is set ?

Usecase

  • We will implement 4 environments (dev, qa, staging and prod) using single set of templates
  • We will use for_each and set combination to do that.
  • For each environment, following Resources will be created with single set of Terraform Configs
  • Resource Group
  • Virtual Network
  • Subnet
  • Public IP & Public Azure DNS Name
  • Network Interface
  • RHEL Virtual machine
  • Provision sample webserver in that RHEL VM

Step-02: Implement complex type cosntructors like list

sets:

  1. Sets do not support element ordering, meaning that traversing sets is not guaranteed to yield the same order each time and that their elements can not be accessed in a targeted way.
  2. They contain unique elements repeated exactly once, and specifying the same element multiple times will result in them being coalesced with only one instance being present in the set.
  3. Declaring a set is similar to declaring a list, the only difference being the type of the variable:
# 2. Environment Name
variable "environment" {
  description = "Environment Name"
  type = set(string)
  default = ["dev1", "qa1", "staging1", "prod1"]
}

Step-03: c2-variables.tf

  • Define the Input Variable Type set for environment.
# 2. Environment Name
variable "environment" {
  description = "Environment Name"
  type = set(string)
  default = ["dev1", "qa1", "staging1", "prod1"]
}

Step-04: terraform.tfvars

  • Core focus on variables will be on environment variable of type set
  • Rest variables are hard-coded in those respective resources.
  • Review environment variable in terraform.tfvars
business_unit = "it"
environment = ["dev2", "myqa2", "staging2", "prod2"]
resoure_group_name = "rg"

Step-05: c1-versions.tf

  • As we are going to create 4 environments, our Random String Resource also need to be traversed in for_each loop to create 4 random strings per environment
  • Create 4 Random Strings using for_each with set variable var.environment
# Random String Resource
resource "random_string" "myrandom" {
  for_each = var.environment
  length = 6
  upper = false 
  special = false
  number = false   
}

Step-06: c3-resource-group.tf

  • Create 4 Resource Groups using for_each with set variable var.environment
# Resource-1: Azure Resource Group
resource "azurerm_resource_group" "myrg" {
  for_each = var.environment
  name = "${var.business_unit}-${each.key}-${var.resoure_group_name}"
  location = var.resoure_group_location
}

Step-07: c4-virtual-network.tf - Virtual Network

  • Create 4 Virtual Networks using for_each with set variable var.environment
  • One Virtual Network will be created in each Resource Group
# Create Virtual Network
resource "azurerm_virtual_network" "myvnet" {
  for_each = var.environment
  name                = "${var.business_unit}-${each.key}-${var.virtual_network_name}"
  address_space       = ["10.0.0.0/16"]
  location            = azurerm_resource_group.myrg[each.key].location
  resource_group_name = azurerm_resource_group.myrg[each.key].name
}

Step-08: c4-virtual-network.tf - Subnet

  • Create 4 Subnets using for_each with set variable var.environment
  • One Subnet will be created in each Virtual Network
# Create Subnet
resource "azurerm_subnet" "mysubnet" {
  for_each = var.environment
  #name                 = "mysubnet-1"
  name = "${var.business_unit}-${each.key}-${var.virtual_network_name}-mysubnet"
  resource_group_name  = azurerm_resource_group.myrg[each.key].name
  virtual_network_name = azurerm_virtual_network.myvnet[each.key].name
  address_prefixes     = ["10.0.2.0/24"]
}

Step-09: c4-virtual-network.tf - Public IP

  • Create 4 Public IPs using for_each with set variable var.environment
  • One Public IP will be created and associated to respective Network Interface in each Virtual Network
# Create Public IP Address
resource "azurerm_public_ip" "mypublicip" {
  for_each = var.environment
  #name                = "mypublicip-1"
  name = "${var.business_unit}-${each.key}-${var.virtual_network_name}-mypublicip"  
  resource_group_name = azurerm_resource_group.myrg[each.key].name
  location            = azurerm_resource_group.myrg[each.key].location
  allocation_method   = "Static"
  #domain_name_label = "app1-vm-${random_string.myrandom[each.key].id}"
   domain_name_label = "app1-vm-${each.key}-${random_string.myrandom[each.key].id}"
  tags = {
    environment = "Dev"
  }
}

Step-10: c4-virtual-network.tf - Network Interface

  • Create 4 Network Interfaces using for_each with set variable var.environment
  • One Network Interface will be created and associated to respective Virtual Machine in each Virtual Network
# Create Network Interface
resource "azurerm_network_interface" "myvmnic" {
  for_each = var.environment
  #name                = "vmnic"
  name = "${var.business_unit}-${each.key}-${var.virtual_network_name}-myvmnic"    
  location            = azurerm_resource_group.myrg[each.key].location
  resource_group_name = azurerm_resource_group.myrg[each.key].name

  ip_configuration {
    name                          = "internal"
    subnet_id                     = azurerm_subnet.mysubnet[each.key].id
    private_ip_address_allocation = "Dynamic"
    public_ip_address_id = azurerm_public_ip.mypublicip[each.key].id 
  }
}

Step-11: c5-linux-virtual-machine.tf - Linux Virutal Machine

  • Create 4 Virtual Machines using for_each with set variable var.environment
  • One Virtual Machine will be created in each Virtual Network and associated to respective Network Interface
# Resource: Azure Linux Virtual Machine
resource "azurerm_linux_virtual_machine" "mylinuxvm" {
  for_each = var.environment
  name                = "mylinuxvm-${each.key}"
  computer_name       = "devlinux-${each.key}" # Hostname of the VM
  resource_group_name = azurerm_resource_group.myrg[each.key].name
  location            = azurerm_resource_group.myrg[each.key].location
  size                = "Standard_DS1_v2"
  admin_username      = "azureuser"
  network_interface_ids = [azurerm_network_interface.myvmnic[each.key].id]
  admin_ssh_key {
    username   = "azureuser"
    public_key = file("${path.module}/ssh-keys/terraform-azure.pub")
  }
  os_disk {
    name = "osdisk${each.key}"
    caching              = "ReadWrite"
    storage_account_type = "Standard_LRS"
    #disk_size_gb = 20
  }
  source_image_reference {
    publisher = "RedHat"
    offer     = "RHEL"
    sku       = "83-gen2"
    version   = "latest"
  }
  custom_data = filebase64("${path.module}/app-scripts/app1-cloud-init.txt")
}

Step-12: Execute Terraform Commands

# Initialize Terraform
terraform init

# Validate Terraform configuration files
terraform validate

# Format Terraform configuration files
terraform fmt

# Review the terraform plan
terraform plan 

# Terraform Apply
terraform apply -auto-approve

# Observation
1. Verify 4 Random Resources created
2. Verify 4 Resource Groups created
3. Verify 4 Virtual Networks created
4. Verify 4 Subnets created
5. Verify 4 Network Interfaces created
6. Verify 4 Virtual Machines created
7. Verify 4 public ips created
8. Verify Disks for Virtual Machines - 4 osdisk created

# Access Sample App
## Root Context
http://app1-vm-dev2-yjedfa.eastus.cloudapp.azure.com
http://app1-vm-myqa2-ysutkd.eastus.cloudapp.azure.com
http://app1-vm-prod2-qoaqpq.eastus.cloudapp.azure.com
http://app1-vm-staging2-pcyeuc.eastus.cloudapp.azure.com

## App1 Context
http://app1-vm-dev2-yjedfa.eastus.cloudapp.azure.com/app1/index.html
http://app1-vm-myqa2-ysutkd.eastus.cloudapp.azure.com/app1/index.html
http://app1-vm-prod2-qoaqpq.eastus.cloudapp.azure.com/app1/index.html
http://app1-vm-staging2-pcyeuc.eastus.cloudapp.azure.com/app1/index.html

## metadata.html
http://app1-vm-dev2-yjedfa.eastus.cloudapp.azure.com/app1/metadata.html
http://app1-vm-myqa2-ysutkd.eastus.cloudapp.azure.com/app1/metadata.html
http://app1-vm-prod2-qoaqpq.eastus.cloudapp.azure.com/app1/metadata.html
http://app1-vm-staging2-pcyeuc.eastus.cloudapp.azure.com/app1/metadata.html

Step-10: Clean-Up

# Destroy Resources
terraform destroy -auto-approve

# Delete Files
rm -rf .terraform* 
rm -rf terraform.tfstate*

References