Skip to content

Moved block ordering possibly incorrect for module with multiple previously moved resources #31489

@mhann-spotlightsportsgroup

Description

Terraform Version

1.2.5

Terraform Configuration Files

Config v1:

# Create ALB target group for app
resource "aws_alb_target_group" "app" {
  name        = "${var.environment}-${var.app_name}"
  port        = var.container_port
  protocol    = "HTTP"
  vpc_id      = data.terraform_remote_state.infrastructure.outputs.vpc.id
  target_type = "ip"

  health_check {
    path                = var.health_check_endpoint
    healthy_threshold   = var.health_check_healthy_threshold
    unhealthy_threshold = var.health_check_unhealthy_threshold
    timeout             = var.health_check_timeout
    interval            = var.health_check_interval
    matcher             = var.health_check_return_codes
  }
}

# Create ALB listener rule
resource "aws_lb_listener_rule" "static" {
  listener_arn = data.terraform_remote_state.infrastructure.outputs.public_listener.arn

  action {
    type             = "forward"
    target_group_arn = aws_alb_target_group.app.arn
  }

  condition {
    host_header {
      values = ["${var.app_name}.*"]
    }
  }
}

Config v2

moved {
  from = aws_alb_target_group.app
  to   = module.alb.aws_alb_target_group.app
}

moved {
  from = aws_lb_listener_rule.static
  to   = module.alb.aws_lb_listener_rule.static
}

module "alb" {
  source = "./modules/alb"

  environment                      = var.environment
  app_name                         = var.app_name
  vpc_id                           = data.terraform_remote_state.infrastructure.outputs.vpc.id
  container_port                   = var.container_port
  health_check_endpoint            = var.health_check_endpoint
  health_check_healthy_threshold   = var.health_check_healthy_threshold
  health_check_unhealthy_threshold = var.health_check_unhealthy_threshold
  health_check_timeout             = var.health_check_timeout
  health_check_interval            = var.health_check_interval
  health_check_return_codes        = var.health_check_return_codes
  listener_arn                     = data.terraform_remote_state.infrastructure.outputs.public_listener.arn
}

Config v3

moved {
  from = aws_alb_target_group.app
  to   = module.alb.aws_alb_target_group.app
}

moved {
  from = aws_lb_listener_rule.static
  to   = module.alb.aws_lb_listener_rule.static
}

moved {
  from = module.alb
  to   = module.alb[0]
}

module "alb" {
  count = var.enable_application_load_balancer ? 1 : 0

  source = "./modules/alb"

  environment                      = var.environment
  app_name                         = var.app_name
  vpc_id                           = data.terraform_remote_state.infrastructure.outputs.vpc.id
  container_port                   = var.container_port
  health_check_endpoint            = var.health_check_endpoint
  health_check_healthy_threshold   = var.health_check_healthy_threshold
  health_check_unhealthy_threshold = var.health_check_unhealthy_threshold
  health_check_timeout             = var.health_check_timeout
  health_check_interval            = var.health_check_interval
  health_check_return_codes        = var.health_check_return_codes
  listener_arn                     = data.terraform_remote_state.infrastructure.outputs.public_listener.arn
}

Debug Output

Snippet of the move application logic output here for public viewing:

2022-07-21T10:47:46.804Z [DEBUG] Building and walking plan graph for NormalMode
2022-07-21T10:47:46.804Z [TRACE] refactoring.ApplyMoves: Processing 'moved' statements in the configuration
  aws_alb_target_group.app[*]->module.alb.aws_alb_target_group.app[*]
  aws_appautoscaling_policy.ecs_policy[*]->module.ecs.aws_appautoscaling_policy.ecs_policy[*]
  aws_appautoscaling_policy.ecs_policy_memory[*]->module.ecs.aws_appautoscaling_policy.ecs_policy_memory[*]
  aws_appautoscaling_target.ecs_target[*]->module.ecs.aws_appautoscaling_target.ecs_target[*]
  aws_cloudwatch_log_group.main[*]->module.ecs.aws_cloudwatch_log_group.main[*]
  aws_ecs_service.main[*]->module.ecs.aws_ecs_service.main[*]
  aws_ecs_task_definition.app[*]->module.ecs.aws_ecs_task_definition.app[*]
  aws_lb_listener_rule.static[*]->module.alb.aws_lb_listener_rule.static[*]
  aws_security_group.ecs_tasks[*]->module.ecs.aws_security_group.ecs_tasks[*]
  module.alb->module.alb[0]
    aws_alb_target_group.app[*]->module.alb.aws_alb_target_group.app[*]
    aws_lb_listener_rule.static[*]->module.alb.aws_lb_listener_rule.static[*]
2022-07-21T10:47:46.804Z [TRACE] refactoring.ApplyMoves: resource aws_ecs_task_definition.app has moved to module.ecs.aws_ecs_task_definition.app
2022-07-21T10:47:46.804Z [TRACE] refactoring.ApplyMoves: resource aws_ecs_service.main has moved to module.ecs.aws_ecs_service.main
2022-07-21T10:47:46.804Z [TRACE] refactoring.ApplyMoves: resource aws_cloudwatch_log_group.main has moved to module.ecs.aws_cloudwatch_log_group.main
2022-07-21T10:47:46.804Z [TRACE] refactoring.ApplyMoves: resource aws_alb_target_group.app has moved to module.alb.aws_alb_target_group.app
2022-07-21T10:47:46.804Z [TRACE] refactoring.ApplyMoves: module.alb has moved to module.alb[0]
2022-07-21T10:47:46.804Z [TRACE] refactoring.ApplyMoves: resource aws_lb_listener_rule.static has moved to module.alb.aws_lb_listener_rule.static
2022-07-21T10:47:46.804Z [TRACE] refactoring.ApplyMoves: resource aws_security_group.ecs_tasks has moved to module.ecs.aws_security_group.ecs_tasks

And the full (encrypted with TF security team pubkey) output here: plan.gpg.log

Expected Behavior

After upgrading the module code above directly from v1 to v3 aws_alb_target_group.app and aws_lb_listener_rule.static should be first moved into module.alb.aws_* and then moved into module.alb[0].aws_*

Actual Behavior

aws_lb_listener_rule.static is moved into module.alb but not the next step into module.alb[0]. Terraform then tries to delete the existing resource, and create a new one at module.alb[0]

  # module.alb.aws_lb_listener_rule.static will be destroyed
  # (because module.alb is not in configuration)

  # (moved from aws_lb_listener_rule.static)
  - resource "aws_lb_listener_rule" "static" {

...snip...

  # module.alb[0].aws_lb_listener_rule.static will be created
  + resource "aws_lb_listener_rule" "static" {
...

Interestingly, the target group completes both moves successfully, despite as far as I can tell the moved blocks being functionally identical between them.

  # aws_alb_target_group.app has moved to module.alb[0].aws_alb_target_group.app
    resource "aws_alb_target_group" "app" {

Steps to Reproduce

Additional Context

There's a lot of wrapper scripts around terraform in a fairly complicated CI setup, but it ultimately boils down to this command:

            "terraform plan -no-color -detailed-exitcode",
            f"-var-file {tfvars}",
            f"-var environment={args['env']}",
            f"-var aws_region={args['aws_default_region']}",
            f"-var app_name={args['app_name']}",
            f"-var project_name={args['project_name']}",
            f"-var ecr_string={args['ecr_string']}",
            f"-var fargate_cpu={args['fargate_cpu']}",
            f"-var fargate_memory={args['fargate_memory']}",
            f"-var desired_count={args['desired_count']}",
            f"-var health_check_endpoint={args['health_check_endpoint']}",
            f"-var health_check_return_codes={args['health_check_return_codes']}",
            f"-var container_port={args['container_port']}",
            f"-var enable_autoscaling={args['enable_autoscaling']}",
            f"-var git_short_hash={args['git_short_hash']}",
            "-out terraform.plan",

We've also seen this across multiple state files - when I first saw it we thought it might just be something weird about that specific state, however we've now seen this a second time with the same resources (aws_lb_listener_rule not working, but aws_alb_target_group working)

References

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions