Black Dynamite
Black Dynamite

Reputation: 4147

Terraform 0.12: Output list of buckets, use as input for another module and iterate

I'm using Tf 0.12. I have an s3 module that outputs a list of buckets, that I would like to use as an input for a cloudfront module that I've got.

The problem I'm facing is that when I do terraform plan/apply I get the following error count.index is 0 |var.redirect-buckets is tuple with 1 element

I've tried all kinds of splats moving the count.index call around to no avail. My sample code is below.

module.s3

resource "aws_s3_bucket" "redirect" {
  count = length(var.redirects)

  bucket = element(var.redirects, count.index)
}
mdoule.s3.output
output "redirect-buckets" {
  value = [aws_s3_bucket.redirect.*]
}
module.cdn.variables
...
variable "redirect-buckets" {
  description = "Redirect buckets"
  default = []
}
....

The error is thrown down here

module.cdn

resource "aws_cloudfront_distribution" "redirect" {
  count = length(var.redirect-buckets)

  default_cache_behavior {
    // Line below throws the error, one amongst many
    target_origin_id = "cloudfront-distribution-origin-${var.redirect-buckets[count.index]}.s3.amazonaws.com"
....
    //Another error throwing line
    target_origin_id = "cloudfront-distribution-origin-${var.redirect-buckets[count.index]}.s3.amazonaws.com"

Any help is greatly appreciated.

Upvotes: 4

Views: 1381

Answers (1)

Alain O'Dea
Alain O'Dea

Reputation: 21686

module.s3

resource "aws_s3_bucket" "redirects" {
  for_each = var.redirects

  bucket = each.value
}

Your variable definition for redirects needs to change to something like this:

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

module.s3.output:

output "redirect_buckets" {
  value = aws_s3_bucket.redirects
}

module.cdn

resource "aws_cloudfront_distribution" "redirects" {
  for_each = var.redirect_buckets

  default_cache_behavior {
    target_origin_id = "cloudfront-distribution-origin-${each.value.id}.s3.amazonaws.com"
}

Your variable definition for redirect-buckets needs to change to something like this (note underscores, using skewercase is going to behave strangely in some cases, not worth it):

variable "redirect_buckets" {
  type = map(object(
    {
      id = string
    }
  ))
}

root module

module "s3" {
  source = "../s3" // or whatever the path is
  redirects = {
    site1 = "some-bucket-name"
    site2 = "some-other-bucket"
  }
}

module "cdn" {
  source = "../cdn" // or whatever the path is
  redirects_buckets = module.s3.redirect_buckets
}

From an example perspective, this is interesting, but you don't need to use outputs from S3 here since you could just hand the cdn module the same map of redirects and use for_each on those.

There is a tool called Terragrunt which wraps Terraform and supports dependencies.

https://terragrunt.gruntwork.io/docs/features/execute-terraform-commands-on-multiple-modules-at-once/#dependencies-between-modules

Upvotes: 1

Related Questions