Passing variables from one nested module to another nested module (terraform and AWS)

Viewed 40

Edited to include root configuration:

I have a terraform module, called ecs-app, which in itself is just one module that I'm calling at the root level. Inside the ecs-app module, I have 30 different services identified, and separated into it's own tf file per service.

The root looks like (only showing the one module in question, the rest work fine):

module "aws-ecs-app" {
  source = "/Users/bshutter/Dev/ghorg/kion/delivery-support/terraform-modules/terraform-aws-ecs"
  # version     = "0.0.1"
  install_id                                   = local.install_id
  private_subnets                              = module.aws-networking.private_subnets
  vpc_id                                       = module.aws-networking.vpc_id
  private_security_groups                      = [module.aws-networking.private_security_group]
  public_security_groups                       = [module.aws-networking.public_security_group]
  region                                       = var.region
  namespace                                    = local.namespace
  internal_balancer_arn                        = module.terraform-aws-ecs-load-balancers.internal_balancer_arn
  external_balancer_arn                        = module.terraform-aws-ecs-load-balancers.external_balancer_arn
  task_role_arn                                = module.aws-ecs-iam.task_role_arn
  execution_role_arn                           = module.aws-ecs-iam.execution_role_arn
  s3_bucket_envfile                            = module.aws-ecs-lambda-functions.s3_bucket_envfile
  ulb_http                                     = module.terraform-aws-ecs-load-balancers.ulb_http
  ulb_https                                    = module.terraform-aws-ecs-load-balancers.ulb_https
  external_lb_https_webapi                     = module.terraform-aws-ecs-load-balancers.external_lb_https_webapi
  aws_lb_target_group_lb_https                 = module.terraform-aws-ecs-load-balancers.aws_lb_target_group_lb_https
  aws_lb_target_group_ulb_http                 = module.terraform-aws-ecs-load-balancers.aws_lb_target_group_ulb_http
  aws_lb_target_group_external_lb_https_webapi = module.terraform-aws-ecs-load-balancers.aws_lb_target_group_external_lb_https_webapi
  aws_lb_target_group_external_lb_http_webapi  = module.terraform-aws-ecs-load-balancers.aws_lb_target_group_external_lb_http_webapi
  aws_lb_target_group_api                      = module.terraform-aws-ecs-load-balancers.aws_lb_target_group_api
  internal_load_balancer_app_url               = module.terraform-aws-ecs-load-balancers.internal_load_balancer_app_url
  external_load_balancer_app_url               = module.terraform-aws-ecs-load-balancers.external_load_balancer_app_url
}

Inside of each of those tf files, I'm calling 4 other modules. The folder/file structure where the modules lives looks like:

terraform-modules 
│
└───terraform-aws-ecs
│      service1.tf
│      service2.tf
│      service3.tf
│      variables.tf
│      outputs.tf
│ 
└───terraform-aws-ecs-service
    │   main.tf
    │   variables.tf

As an example, one of the 4 modules is for an ecs-service, in this example: account creation:

module "ecs_service_accountcreation" {
  source           = "/Users/bshutter/Dev/terraform-modules/terraform-aws-ecs-service"
  component_name   = var.service_accountcreation_name
  container_port   = var.container_port_accountcreation
  target_group_arn = aws_lb_target_group.accountcreation.arn
  task_definition  = module.taskdefinition_accountcreation
}

I'm running into issues where I'm setting these variables here, and adding a section in the other modules's variables.tf files, and expecting that variable to pass through, but it's not.

As an example, the terraform-aws-ecs-service module's main.tf looks like:

resource "aws_ecs_service" "service" {
  cluster                            = aws_ecs_cluster.app.arn
  deployment_maximum_percent         = var.service_deployment_max_percent
  deployment_minimum_healthy_percent = var.service_deployment_min_healthy_percent
  desired_count                      = var.service_desired_count
  enable_ecs_managed_tags            = var.service_enable_ecs_managed_tags
  enable_execute_command             = var.enable_ecs_exec
  health_check_grace_period_seconds  = var.service_health_check_grace_period_seconds
  launch_type                        = var.service_launch_type
  name                               = "${var.namespace}-${var.component_name}-${var.service_label}-${var.install_id}"
  platform_version                   = var.service_platform_version
  propagate_tags                     = var.service_propagate_tags
  scheduling_strategy                = var.service_scheduling_strategy
  task_definition                    = var.task_definition

  deployment_circuit_breaker {
    enable   = var.service_deployment_circuit_breaker_enabled
    rollback = var.service_deployment_circuit_breaker_rollback
  }

  deployment_controller {
    type = var.service_deployment_controller_type
  }

  load_balancer {
    container_name   = var.component_name
    container_port   = var.container_port
    target_group_arn = var.target_group_arn
  }

  network_configuration {
    assign_public_ip = var.service_assign_public_ip
    security_groups  = var.private_security_groups
    subnets          = var.private_subnets
  }
}

And the variables.tf looks like:

variable "enable_ecs_exec" {
  type        = bool
  default     = true
  description = "This will set 'EnableExecuteCommand' to true on ECS services. This allows using the AWS CLI to run commands on running containers or create interactive sessions. This also attaches an additional IAM policy to ensure ECS tasks have permissions to create data channels through SSM."
}

variable "service_launch_type" {
  type        = string
  description = "Launch Type for ECS Service"
  default     = "FARGATE"
}

variable "service_deployment_max_percent" {
  type    = number
  default = 200
}

variable "service_deployment_min_healthy_percent" {
  type    = number
  default = 100
}

variable "service_desired_count" {
  type    = number
  default = 1
}

variable "service_enable_ecs_managed_tags" {
  type    = bool
  default = false
}

variable "service_health_check_grace_period_seconds" {
  type    = number
  default = 0
}

variable "service_platform_version" {
  type    = string
  default = "LATEST"
}

variable "service_propagate_tags" {
  type    = string
  default = "NONE"
}

variable "service_scheduling_strategy" {
  type    = string
  default = "REPLICA"
}

variable "service_deployment_circuit_breaker_enabled" {
  type    = bool
  default = false
}

variable "service_deployment_circuit_breaker_rollback" {
  type    = bool
  default = false
}

variable "service_deployment_controller_type" {
  type    = string
  default = "ECS"
}
variable "service_assign_public_ip" {
  type    = bool
  default = false
}

variable "service_label" {
  type        = string
  default     = "ECSService"
  description = "Name of Service - Primarily Used in Tags"
}

variable "target_group_arn" {
  type = string
}

variable "container_port" {
  type = string
}

variable "component_name" {
  type = string
}

variable "task_definition" {
  type = string
}

When I run terraform plan, I get the error

│ Error: Unsupported argument
│ 
│   on .terraform/modules/aws-ecs-app/service-accountcreation.tf line 3, in module "ecs_service_accountcreation":
│    3:   component_name   = var.service_accountcreation_name
│ 
│ An argument named "component_name" is not expected here.

I've specifically set a variable for component_name in both the module calling the 4 modules, and the module that has the code for the ecs service.

I'm looking for that variable in these two lines of terraform:

  name  = "${var.namespace}-${var.component_name}-${var.service_label}-${var.install_id}"
  load_balancer {
    container_name   = var.component_name
    container_port   = var.container_port
    target_group_arn = var.target_group_arn
  }

terraform validate works in the terraform-aws-service directory, but not in the root, where I'm calling the module that is referencing the "submodules"

1 Answers

Variables do not "pass through" modules at all. They are always scoped to a specific module. If you want to use that variable in multiple modules you need to declare that variable as an input in every module that needs to use it. In other words, add this to the aws-ecs-app module:

variable "component_name" {
  type = string
}
Related