0

Having a hard time trying to make this work.

I'm trying to use the generate block to add a for_each and run the module multiple times depending on how much entries I have in the variable s3, but having lots of trouble making it right.

This are the important parts of the terragrunt.hcl file

locals {
  s3 = {
    "companies-data-service" = {
      enable_cloudfront        = true
      cloudfront_allowed_paths = ["logos/*"]
      cors_rules = {
        "local" = {
          methods = ["POST", "HEAD", "PUT", "GET"]
          origins = ["http://localhost:*", "https://*.test.io"]
        }
      }
    }
  }
}

generate "cdn" {
  path      = "cdn.tf"
  if_exists = "overwrite"
  contents  = <<EOF
module "cdn" {
  source = "git::[email protected]:my-org/terraform-modules.git//s3?ref=v0.0.21"
  for_each = { for $${k}, $${v} in "${local.s3}" : $${k} => $${v} }

  name                     = "${local.s3}" != {} ? $${each.value} : ""
  environment              = "${local.parent.inputs.core_env_name}"
  cors_rules               = try($${each.value.cors_rules}, {})
  enable_cloudfront        = try($${each.value.enable_cloudfront}, false)
  enable_versioning        = try($${each.value.enable_versioning}, false)
  cloudfront_allowed_paths = try($${each.value.cloudfront_allowed_paths}, [])
  acm_certificate_arn      = "${dependency.acm.outputs.acm_certificate_arn}"
  aliases                  = ["$${each.key}-static.test.com"]

  enable_lifecycle_rules = try($${each.value.enable_lifecycle_rules}, false)
  s3_lifecycle_rules     = try($${each.value.lifecycle_rules}, [])
  bucket_policies        = try($${each.value.bucket_policies}, {})
}
EOF
}

Having these errors

local.s3 as object with 1 attribute "companies-data-service" 
ERRO[0010] .
                                           
ERRO[0010] Cannot include the given value in a string template: string required.
 
ERRO[0010] Error: Invalid template interpolation value

Also tried the local.s3 variable like this:

s3 = {
    companies = {
      name = "companies"
      enable_cloudfront        = true
      cloudfront_allowed_paths = ["logos/*"]
      cors_rules = {
        "local" = {
          methods = ["POST", "HEAD", "PUT", "GET"]
          origins = ["http://localhost:*", "https://*.test.io"]
        }
      }
    },
    companies2 = {
      name = "companies-2"
      enable_cloudfront        = true
      cloudfront_allowed_paths = ["logos/*"]
      cors_rules = {
        "local" = {
          methods = ["POST", "HEAD", "PUT", "GET"]
          origins = ["http://localhost:*", "https://*.test.io"]
        }
      }
    }
  }

And block generate like this:

generate "cdn" {
  path      = "cdn.tf"
  if_exists = "overwrite"
  contents  = <<EOF
module "cdn" {
  source = "git::[email protected]:my-org/terraform-modules.git//s3?ref=v0.0.21"
  for_each = "${local.s3}"

  name                     = $${each.value.name}
  environment              = "${local.parent.inputs.core_env_name}"
  cors_rules               = try($${each.value.cors_rules}, {})
  enable_cloudfront        = try($${each.value.enable_cloudfront}, false)
  enable_versioning        = try($${each.value.enable_versioning}, false)
  cloudfront_allowed_paths = try($${each.value.cloudfront_allowed_paths}, [])
  acm_certificate_arn      = "${dependency.acm.outputs.acm_certificate_arn}"
  aliases                  = ["$${each.value.name}-static.test.com"]

  enable_lifecycle_rules = try($${each.value.enable_lifecycle_rules}, false)
  s3_lifecycle_rules     = try($${each.value.lifecycle_rules}, [])
  bucket_policies        = try($${each.value.bucket_policies}, {})
}
EOF
}

To validate my changes I tried to pass the locals inside the generate block like pure terraform code, that way it works.

generate "cdn" {
  path      = "cdn.tf"
  if_exists = "overwrite"
  contents  = <<EOF
locals {
  s3 = {
    companies = {
      name = "companies"
      enable_cloudfront        = true
      cloudfront_allowed_paths = ["logos/*"]
      cors_rules = {
        "local" = {
          methods = ["POST", "HEAD", "PUT", "GET"]
          origins = ["http://localhost:*", "https://*.test.io"]
        }
      }
    },
    companies2 = {
      name = "companies-2"
      enable_cloudfront        = true
      cloudfront_allowed_paths = ["logos/*"]
      cors_rules = {
        "local" = {
          methods = ["POST", "HEAD", "PUT", "GET"]
          origins = ["http://localhost:*", "https://*.test.io"]
        }
      }
    }
  }
}
module "cdn" {
  source = "git::[email protected]:my-org/terraform-modules.git//s3?ref=v0.0.21"
  for_each = local.s3

  name                     = each.value.name
  environment              = "${local.parent.inputs.core_env_name}"
  cors_rules               = try(each.value.cors_rules, {})
  enable_cloudfront        = try(each.value.enable_cloudfront, false)
  enable_versioning        = try(each.value.enable_versioning, false)
  cloudfront_allowed_paths = try(each.value.cloudfront_allowed_paths, [])
  acm_certificate_arn      = "${dependency.acm.outputs.acm_certificate_arn}"
  aliases                  = ["$${each.value.name}-static.test.com"]
  enable_lifecycle_rules = try(each.value.enable_lifecycle_rules, false)
  s3_lifecycle_rules     = try(each.value.lifecycle_rules, [])
  bucket_policies        = try(each.value.bucket_policies, {})
}
EOF
}
```

So the issue is clearly with how terragrunt is passing the variable to the generate block, but I don't what is happening because terragrunt don't output anything I can use to debug that variable.

Any help will be much appreciated

1 Answer 1

0

This is a terragrunt file, therefore locals is consumed inside terragrunt, and you cannot pass it to terraform. Terragrunt only generates the tf files and execute the terraform command. you need to pass the locals to terraform and you can use

inputs = {
    s3 = local.s3
}

generate "vars" {
    path      = "vars.tf"
    if_exists = "overwrite"
    contents  = <<EOF
variable "s3" {
  type = object({})
}
EOF
}

and then the cdn block can be written in

generate "cdn" {
  path      = "cdn.tf"
  if_exists = "overwrite"
  contents  = <<EOF
module "cdn" {
  source = "git::[email protected]:my-org/terraform-modules.git//s3?ref=v0.0.21"
  for_each = { for k, v in s3 : k => v }

  name                     = s3 != {} ? each.value : ""
  environment              = "${local.parent.inputs.core_env_name}"
  cors_rules               = try(each.value.cors_rules, {})
  enable_cloudfront        = try(each.value.enable_cloudfront, false)
  enable_versioning        = try(each.value.enable_versioning, false)
  cloudfront_allowed_paths = try(each.value.cloudfront_allowed_paths, [])
  acm_certificate_arn      = "${dependency.acm.outputs.acm_certificate_arn}"
  aliases                  = ["$${each.key}-static.test.com"]

  enable_lifecycle_rules = try(each.value.enable_lifecycle_rules, false)
  s3_lifecycle_rules     = try(each.value.lifecycle_rules, [])
  bucket_policies        = try(each.value.bucket_policies, {})
}
EOF
}

I have replaced "${dependency.acm.outputs.acm_certificate_arn}" and "${local.parent.inputs.core_env_name}" with static values (I didn't have the values) and source = "vancluever/module/null", and it worked.

Sign up to request clarification or add additional context in comments.

1 Comment

Nice I'll give it a shot.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.