4

I am using terraform via terragrunt. I have a folder with a single terragrunt.hcl file in it. The purpose of this file is to create multiple subnetworks in GCP.

To create a subnetwork, I have a module that takes several inputs.

I want to be able to create several subnetworks in my terragrunt.hcl file.

I think the best way would be to create a list with dictionaries (or maps as terraform call them) and then iterate over them.

I have some code that is not working

Here is some non-working code.

#terragrunt.hcl

include {
  path = find_in_parent_folders()
}

  inputs = {
    # Common tags to be assigned to all resources
    subnetworks = [
      {
        "subnetName": "subnet1-euw"
        "subNetwork": "10.2.0.0/16"
        "region": "europe-west1"
      },
      {
        "subnetName": "subnet1-usc1"
        "subNetwork": "10.3.0.0/16"
        "region": "us-central1"
      }
    ]
  }

terraform {
  module "subnetworks" {
    source = "github.com/MyProject/infrastructure-modules.git//vpc/subnetwork"
    vpc_name = "MyVPC"
    vpc_subnetwork_name = [for network in subnetworks: network.subnetName]
    vpc_subnetwork_cidr = [for network in subnetworks: network.subNetwork]
    vpc_subnetwork_region = [for network in subnetworks: network.region]
  }
}

Seems I cannot use "module" inside the "terraform" block. Hopefully the code at least show what I want to achieve.

For reference, the module I am calling looks like this

#main.tf

terraform {
  # Intentionally empty. Will be filled by Terragrunt.
  backend "gcs" {}
}

resource "google_compute_subnetwork" "vpc_subnetwork" {
  name          = var.vpc_subnetwork_name
  ip_cidr_range = var.vpc_subnetwork_cidr
  region        = var.vpc_subnetwork_region
  network       = var.vpc_name
}
#variables.tf
variable "vpc_name" {
  description = "Name of VPC"
  type        = string
}

variable "vpc_subnetwork_name" {
  description = "Name of subnetwork"
  type        = string
}

variable "vpc_subnetwork_cidr" {
  description = "Subnetwork CIDR"
  type        = string
}

variable "vpc_subnetwork_region" {
  description = "Subnetwork region"
  type        = string
}
Johnathan
  • 737
  • 2
  • 7
  • 21

1 Answers1

2

Terragrunt does not have a loop construct. In Terragrunt, you'd use a directory hierarchy to do what you want here. For example, to achieve your goals above, something like this:

└── live
    ├── empty.yaml
    ├── euw
    │   ├── region.yaml
    │   └── vpc
    │       └── terragrunt.hcl
    ├── terragrunt.hcl
    └── usc1
        ├── region.yaml
        └── vpc
            └── terragrunt.hcl

Within live/terragrunt.hcl, you make the other yaml files available within the terragrunt configuration:

# live/terragrunt.hcl
inputs = merge(
  # Configure Terragrunt to use common vars encoded as yaml to help you keep often-repeated variables (e.g., account ID)
  # DRY. We use yamldecode to merge the maps into the inputs, as opposed to using varfiles due to a restriction in
  # Terraform >=0.12 that all vars must be defined as variable blocks in modules. Terragrunt inputs are not affected by
  # this restriction.
  yamldecode(
    file("${get_terragrunt_dir()}/${find_in_parent_folders("region.yaml", "${path_relative_from_include()}/empty.yaml")}"),
  )
)

In the region.yaml within each region, you simply state the region:

# live/euw/region.yaml
# These variables apply to this entire region. They are automatically pulled in using the extra_arguments
# setting in the root terraform.tfvars file's Terragrunt configuration.
region: "europe-west1"
# live/usc1/region.yaml
region: "us-central1"

Now you can refer to the region in your per-region terragrunt.hcl files as a variable:

# live/euw/vpc/terragrunt.hcl
terraform {
  source = "github.com/MyProject/infrastructure-modules.git//vpc/subnetwork"
}

include {
  path = find_in_parent_folders()
}

inputs = {
  vpc_subnetwork_name = "subnet1-${region}"
  vpc_subnetwork_cidr = "10.2.0.0/16"
  vpc_subnetwork_region = region
  vpc_name = "MyVPC"
}

Also:

# live/usc1/vpc/terragrunt.hcl
terraform {
  source = "github.com/MyProject/infrastructure-modules.git//vpc/subnetwork"
}

include {
  path = find_in_parent_folders()
}

inputs = {
  vpc_subnetwork_name = "subnet1-${region}"
  vpc_subnetwork_cidr = "10.3.0.0/16"
  vpc_subnetwork_region = region
  vpc_name = "MyVPC"
}

You might find the example terragrunt repository from Gruntwork helpful.

Ben Whaley
  • 32,811
  • 7
  • 87
  • 85
  • In your example you are setting the same CIDR for multiple regions. As you see in my example, separate regions have separate CIDRs. If you can include both the subnetworks from my example in yours, this might be more clear. thanks! – Johnathan Feb 04 '20 at 06:12
  • Sure, I thought it was clear from the layout, but I updated it to explicit. – Ben Whaley Feb 04 '20 at 15:35
  • what if we need to represent a map in the yaml file? – Joseph T F Feb 26 '20 at 19:12