skip to Main Content

I’m using Terraform to create an AWS API Gateway and 2 Lambda functions.

I would like to know if there is a way to apply for_each to only a particular block from locals while using the modules. For the remaining variables in modules, I want it to either pick up from variables.tf or from locals:

Below is my code:

locals {
  lambda_apigateway = {
    "digitalts-devtest-${var.environment}-auth" = {
      service_name          = "${var.environment}-auth"
      function_handler      = "auth.handler"
      lambda_key            = "customizedlayer.zip"
      function_name         = "${var.account}-${var.environment}"
      source_dir            = "../built/lambdahandlers/auth/"
      output_path           = "../auth.zip"
      layer_name            = var.layer_name
      create_lambda_layer   = var.create_lambda_layer
      #layers                           = var.layers
      layer_count                       = var.layer_count
      filename                          = var.filename
      #create_lambda_permission          = var.create_lambda_permission
      #create_lambda                     = var.create_lambda
      environment_variables = {
        "MATRIS_CREDENTIALS" = "MATRIS_CLIENT"
      }
    },

    "digitalts-devtest-${var.environment}-healthz" = {
      service_name          = "${var.environment}-healthz"
      function_handler      = "healthz.handler"
      lambda_key            = "customizedlayer.zip"
      function_name         = "${var.account}-${var.environment}"
      source_dir            = "../built/lambdahandlers/healthz/"
      output_path           = "../healthz.zip"
      layer_name            = var.layer_name
      create_lambda_layer   = var.create_lambda_layer
      #layers                           = var.layers
      layer_count           = var.layer_count
      filename              = var.filename
      environment_variables = {
        "MATRIS_CREDENTIALS" = "MATRIS_CLIENT"
      }
    }
   }
    
  api_gateway_variables = {
    create_apigw_rest               = var.create_apigw_rest
    create_apigw                    = var.create_apigw
    api_gateway_name                = var.api_gateway_name
    endpoint_configuration          = var.endpoint_configuration
    parent_path                     = var.parent_path
    first_sub_path                  = var.first_sub_path
    http_methods                    = var.http_methods
    authorizations                  = var.authorizations
    request_parameters              = var.request_parameters
    request_models                  = var.request_models
    integration_http_methods        = var.integration_http_methods
    integration_types               = var.integration_types
    connection_types                = var.connection_types
    uri                             = var.uri
  }
}
    

I tried the following code but it is applying the for_each to all of the locals:

module "lambda_API_dts" {
  source                  = "gitlab.***"
  version                 = "0.0.49"

  for_each                = local.lambda_apigateway
  service_name            = each.key
  lambda_key              = each.value.lambda_key
  function_name           = each.value.function_name
  source_dir              = each.value.source_dir
  output_path             = each.value.output_path
  runtime                 = var.runtime
  function_handler        = var.function_handler
  timeout                 = var.timeout
  memory_size             = var.memory_size
  environment_variables   = each.value.environment_variables
  subnet_ids              = var.subnet_ids
  VPCId                   = var.vpc_id
  env                     = var.env
  filename                = var.filename
  lambda_layer_bucket     = var.lambda_layer_bucket
  s3_key_lambda_layer     = var.s3_key_lambda_layer
  layer_count             = each.value.layer_count

  #api gateway variables
  
  create_apigw_rest               = local.create_apigw_rest
  create_apigw                    = local.create_apigw
  api_gateway_name                = local.api_gateway_name
  endpoint_configuration          = local.endpoint_configuration
  parent_path                     = local.parent_path
  first_sub_path                  = local.first_sub_path
  http_methods                    = local.http_methods
  authorizations                  = local.authorizations
  request_parameters              = local.request_parameters
  request_models                  = local.request_models
  integration_http_methods        = local.integration_http_methods
  integration_types               = local.integration_types
  connection_types                = local.connection_types
  uri                             = local.uri
}

I want only 1 API gateway to be created & 2 Lambdas to be created.

2

Answers


  1. Try using dynamic as follows:

    module "lambda_API_dts" {
      source = "gitlab.***"
      version = "0.0.49"
    
      # digitalts-devtest auth, healthz
    
      dynamic "lambda_apigateway" {
        for_each = local.lambda_apigateway
        content {
          service_name = lambda_apigateway.key
          lambda_key = lambda_apigateway.value.lambda_key
          function_name = lambda_apigateway.value.function_name
          source_dir = lambda_apigateway.value.source_dir
          output_path = lambda_apigateway.value.output_path
          runtime = var.runtime
          function_handler = var.function_handler
          timeout = var.timeout
          memory_size = var.memory_size
          environment_variables = lambda_apigateway.value.environment_variables
          subnet_ids = var.subnet_ids
          VPCId = var.vpc_id
          env = var.env
          filename = var.filename
          lambda_layer_bucket = var.lambda_layer_bucket
          s3_key_lambda_layer = var.s3_key_lambda_layer
          layer_count = lambda_apigateway.value.layer_count
        }
      }
    
      #api gateway variables
    
      create_apigw_rest = local.create_apigw_rest
      create_apigw = local.create_apigw
      api_gateway_name = local.api_gateway_name
      endpoint_configuration = local.endpoint_configuration
      parent_path = local.parent_path
      first_sub_path = local.first_sub_path
      http_methods = local.http_methods
      authorizations = local.authorizations
      request_parameters = local.request_parameters
      request_models = local.request_models
      integration_http_methods = local.integration_http_methods
      integration_types = local.integration_types
      connection_types = local.connection_types
      uri = local.uri
    }
    
    Login or Signup to reply.
  2. @Shlomi, dynamic blocks won’t work here, in a module, as said in the documentation :

    You can dynamically construct repeatable nested blocks […] using a special dynamic block type, which is supported inside resource, data, provider, and provisioner blocks

    Method 1 : Deport the for_each to the resource definition

    If you want to keep the root module as is for a particular reason, you can use for_each in the child module to loop on the desired resource. Below, you’ll find the root module & the child module :

    ./main.tf :

    module "lambda_API_dts" {
      source                  = "gitlab.***"
      version                 = "0.0.49"
    
      # Pass you map of objects to your module #############
      lambda_apigateway = local.lambda_apigateway
    
      runtime                 = var.runtime
      function_handler        = var.function_handler
      timeout                 = var.timeout
      memory_size             = var.memory_size
      subnet_ids              = var.subnet_ids
      VPCId                   = var.vpc_id
      env                     = var.env
      filename                = var.filename
      lambda_layer_bucket     = var.lambda_layer_bucket
      s3_key_lambda_layer     = var.s3_key_lambda_layer
    
      #api gateway variables
      
      [...]
    }
    

    ./modules/lambda_API_dts/main.tf :

    [...]
    
    resource "aws_lambda_function" "test_lambda" {
    
      for_each = var.lambda_apigateway
      
      [...aws_lambda_function properties...]
    }
    
    [...]
    

    Method 2 : Split your modules by purpose

    Here, your lambda_API_dts module seems to have the purpose of creating a AWS API gateway AND AWS lambda functions.

    If you really need to have your for_each block in the calling module, you can keep it there but you can also put the for_each at the resource level, in the resource block, using my example in Method 1.

    .
    ├── api-gw
    │   └── main.tf
    ├── lambda-functions
    │   └── main.tf
    └── main.tf
    

    This way, you will :

    • have your 2 modules that will have their own variables & behavior
    • be able to put all your lambda functions here, not only your "API gateway" ones

    Hope this helps !

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search