Terraform: Using Flags For Settings
Description:
As you start developing Terraform compositions and modules, you will want to optionally deploy resources. We discussed this in a previous post by using the count
meta argument to deploy a resource by setting its value to 1
to deploy and 0
to not deploy. Here is a few more examples:
To Resolve:
-
So
Option 1
is to use count and check for a condtion to deploy a single resource like shown below:1 2 3 4 5 6 7
module "azure_learning_rg" { count = var.region == "southcentralus" ? 1 : 0 source = "git::https://github.com/gerryw1389/terraform-modules.git//resource-group?ref=v1.0.0" resource_group_name = "aa-${var.env_stage_abbr}-${var.region_abbr}-test-remote-2" location = var.region tags = local.sbx_tags }
-
We see in
main.tf
that if the variableregion
is set tosouthcentralus
which is its default invariables.tf
then it will deploy the Resource Group. -
Cool, so it will conditionally deploy that one Resource Group and its associated lock.
-
-
Option 2
is the same as option 1, but will deploy multiple resources. Here I will create a file calledC:\scripts\tf\local-state\blah.tf
:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
terraform { required_providers { azurerm = { source = "hashicorp/azurerm" version = ">3.10.0" } } required_version = ">1.1.0" } provider "azurerm" { client_id = var.client_id client_secret = var.client_secret subscription_id = var.subscription_id tenant_id = var.tenant_id skip_provider_registration = true features {} } variable "tenant_id" { description = "(Required) Service Principal AD Tenant ID - Azure AD for terraform authentication." type = string } variable "subscription_id" { description = "(Required) Azure Subscription Id used to connect to AzureRM provider." type = string } variable "client_id" { description = "(Required) Service Principal App ID - Azure AD for terraform authentication." type = string } variable "client_secret" { description = "(Required) Service Principal Client Secret - Azure AD for terraform authentication." type = string } locals { resource_groups = ["one", "two", "three"] } resource "azurerm_resource_group" "rg" { count = length(local.resource_groups) name = "aa-my-rg-${local.resource_groups[count.index]}" location = "southcentralus" }
- Next I run each command one at a time:
1 2 3
cd C:\scripts\tf\local-state terraform init terraform plan -var-file="env.tfvars" -out="tf.plan"
-
where
env.tfvars
just has stuff to connect to Azure as required variables. -
I get this output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
> terraform plan -var-file="env.tfvars" -out="tf.plan" Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # azurerm_resource_group.rg[0] will be created + resource "azurerm_resource_group" "rg" { + id = (known after apply) + location = "southcentralus" + name = "aa-my-rg-one" } # azurerm_resource_group.rg[1] will be created + resource "azurerm_resource_group" "rg" { + id = (known after apply) + location = "southcentralus" + name = "aa-my-rg-two" } # azurerm_resource_group.rg[2] will be created + resource "azurerm_resource_group" "rg" { + id = (known after apply) + location = "southcentralus" + name = "aa-my-rg-three" } Plan: 3 to add, 0 to change, 0 to destroy.
-
OK, so this will deploy the same number of resources as the number of elements my list object
resource_groups
and will assign whatever their value is to thename
argument forazurerm_resource_group
. -
Cool, but we discussed this before, you should always use for_each instead so that you can update it freely without destroying and recreating all resources:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
terraform { required_providers { azurerm = { source = "hashicorp/azurerm" version = ">3.10.0" } } required_version = ">1.1.0" } provider "azurerm" { client_id = var.client_id client_secret = var.client_secret subscription_id = var.subscription_id tenant_id = var.tenant_id skip_provider_registration = true features {} } variable "tenant_id" { description = "(Required) Service Principal AD Tenant ID - Azure AD for terraform authentication." type = string } variable "subscription_id" { description = "(Required) Azure Subscription Id used to connect to AzureRM provider." type = string } variable "client_id" { description = "(Required) Service Principal App ID - Azure AD for terraform authentication." type = string } variable "client_secret" { description = "(Required) Service Principal Client Secret - Azure AD for terraform authentication." type = string } locals { resource_groups = [ { name = "one" }, { name = "two" }, { name = "three"} ] } resource "azurerm_resource_group" "rg" { for_each = { for rg in local.resource_groups : rg.name => rg } name = "aa-my-rg-${each.value.name}" location = "southcentralus" }
- New output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
> terraform plan -var-file="env.tfvars" -out="tf.plan" Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # azurerm_resource_group.rg["one"] will be created + resource "azurerm_resource_group" "rg" { + id = (known after apply) + location = "southcentralus" + name = "aa-my-rg-one" } # azurerm_resource_group.rg["three"] will be created + resource "azurerm_resource_group" "rg" { + id = (known after apply) + location = "southcentralus" + name = "aa-my-rg-three" } # azurerm_resource_group.rg["two"] will be created + resource "azurerm_resource_group" "rg" { + id = (known after apply) + location = "southcentralus" + name = "aa-my-rg-two" } Plan: 3 to add, 0 to change, 0 to destroy.
-
Here is the “before”:
-
For example, let’s update the code to add ‘bob’ and ‘jim’ resource groups:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
# <...> omitted for brevity locals { resource_groups = [ { name = "one" }, { name = "two" }, { name = "bob"}, { name = "three"}, { name = "jim"} ] } resource "azurerm_resource_group" "rg" { for_each = { for rg in local.resource_groups : rg.name => rg } name = "aa-my-rg-${each.value.name}" location = "southcentralus" }
- This produces this output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
> terraform plan -var-file="env.tfvars" -out="tf.plan" azurerm_resource_group.rg["three"]: Refreshing state... [id=/subscriptions/819cbf70-19ca-4614-b32b-9b8cbceeb10e/resourceGroups/aa-my-rg-three] azurerm_resource_group.rg["two"]: Refreshing state... [id=/subscriptions/819cbf70-19ca-4614-b32b-9b8cbceeb10e/resourceGroups/aa-my-rg-two] azurerm_resource_group.rg["one"]: Refreshing state... [id=/subscriptions/819cbf70-19ca-4614-b32b-9b8cbceeb10e/resourceGroups/aa-my-rg-one] Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # azurerm_resource_group.rg["bob"] will be created + resource "azurerm_resource_group" "rg" { + id = (known after apply) + location = "southcentralus" + name = "aa-my-rg-bob" } # azurerm_resource_group.rg["jim"] will be created + resource "azurerm_resource_group" "rg" { + id = (known after apply) + location = "southcentralus" + name = "aa-my-rg-jim" } Plan: 2 to add, 0 to change, 0 to destroy.
-
And apply:
-
OK, so
Option 3
is where you can use a “flag” to optionally deploy a setting as seen in thismain.tf
around line 25 forserver_farm_delegation
.- Notice that this makes use of the
dynamic
blocks which will deploy settings optionally. - Like the documentation states, these should be used sparingly as they can be confusing when used too often.
- Notice that this makes use of the
Comments