0

I'm having a very hard time trying to understand how to mirror the native Terraform module instantiation structure I am used to in Terragrunt. Take the below Terraform structure that creates different instances of a sns topic module.

module "sns_topic" {
  source  = "terraform-aws-modules/sns/aws"
  version = "~> 3.0"

  name  = "my-topic"
}

module "sns_topic_two" {
  source  = "terraform-aws-modules/sns/aws"
  version = "~> 3.0"

  name  = "my-topic-two"
  content_based_deduplication              = true
}

module "sns_topic_three" {
  source  = "terraform-aws-modules/sns/aws"
  version = "~> 3.0"

  name  = "my-topic-three"
  http_success_feedback_role_arn           = x
  http_success_feedback_sample_rate        = y
  http_failure_feedback_role_arn           = z
}
...

Any of the fields in the module itself could populate a given instance of that module.

I don't understand how to accomplish this in Terragrunt via their Inputs for cases where each instance of the module can vary by the fields uses. For example, in the sns module, you could have Topic A that uses content_based_deduplication and topic B that uses lambda_success_feedback_role_arn and topic C that uses entirely different fields, and you might have 100 different topics in the environment. In native Terraform you'd just instantiate each module as seen above. But how can you do this via Terragrunt?

Howard_Roark
  • 4,088
  • 1
  • 14
  • 24

1 Answers1

1

(Disclaimer: what is below just represents my understanding & workflow, which might not be definitive :) )

My understanding is that whilst you can write native Terraform in the top level module, best practice is to move this to another module, called from the terraform block in your terragrunt.hcl file. This module acts as an orchestration layer. I think the idea is that the top levels of a Terragrunt project likely represent things where you broadly want the same resources in each (for example dev, test, prod) and so the use of this orchestration module allows you to DRY that code up, rather than duplicate it between the top level directories.

Therefore in your case, I think you would need to write a module that looked a little like this and would be called from your terragrunt.hcl file:

top_level/main.tf

variable "sns_topics" {
  type = map(map(string))
}

module "sns_topic" {
  source   = "terraform-aws-modules/sns/aws"
  version  = "~> 3.0"
  for_each = var.sns_topics

  name                           = each.key 
  content_based_deduplication    = lookup(each.value, "content_based_deduplication", null)
  http_success_feedback_role_arn = lookup(each.value, "http_success_feedback_role_arn", null)
}

and then the inputs in your terragrunt.hcl might look a little like this:

inputs = {
  sns_topics = {
    sns_topic = {},
    sns_topic_two = {
      content_based_deduplication = true
    },
    sns_topic_three = {
      http_success_feedback_role_arn = "x"
    }
  }
}

Finally you would then call the top_level module in the terraform block of your terragrunt.hcl

terraform {
  source = "git::git@github.com:<your_account>/modules.git//top_level?ref=v0.0.1"
}

Note: the use of null as the default value in the lookup functions, should result in that parameter being omitted in the case that the specific topic map does not contain that particular key.

This page in the Terragrunt docs talks more about this approach.

clockworknet
  • 2,736
  • 1
  • 15
  • 19