-
Notifications
You must be signed in to change notification settings - Fork 10.3k
Moved block ordering possibly incorrect for module with multiple previously moved resources #31489
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)