hashicorp / terraform-provider-aws

The AWS Provider enables Terraform to manage AWS resources.
https://registry.terraform.io/providers/hashicorp/aws
Mozilla Public License 2.0
9.79k stars 9.14k forks source link

Failing to change aws_route53_record.dns_record from weighted to simple #15706

Open molywitman opened 3 years ago

molywitman commented 3 years ago

Community Note

Terraform CLI and Terraform AWS Provider Version

Affected Resource(s)

Terraform Configuration Files

provider "aws" {
  version = "~> 2.6"
  region = var.aws_region
  allowed_account_ids = [var.aws_account_id]
}

terraform {
  backend "s3" {}
  required_version = ">= 0.12"
}
resource "aws_route53_record" "dns_record" {

  zone_id = data.terraform_remote_state.route53_public.*.outputs.primary_domain_hosted_zone_id[0]
  name    = var.domain_name
  type    = "A"

  set_identifier = var.edge_entry_point ? "alb" : null

  dynamic "weighted_routing_policy" {
    for_each = var.alb_weighted_numbers
    content {
      weight = weighted_routing_policy.value["weight"]
    }
  }

  alias {
    name                   = data.terraform_remote_state.alb.outputs.alb_dns_name
    zone_id                = data.terraform_remote_state.alb.outputs.alb_hosted_zone_id
    evaluate_target_health = true
  }
}

resource "aws_route53_record" "dns_record2" {
  count = var.edge_entry_point ? 1 : 0
  zone_id = data.terraform_remote_state.route53_public.*.outputs.primary_domain_hosted_zone_id[0]
  name    = var.domain_name
  type    = "A"

  set_identifier = var.edge_entry_point ? "edge" : null

  dynamic "weighted_routing_policy" {
    for_each = var.edge_weighted_numbers
    content {
      weight = weighted_routing_policy.value["weight"]
    }
  }

  alias {
    name                   = data.terraform_remote_state.alb.outputs.alb_dns_name
    zone_id                = data.terraform_remote_state.alb.outputs.alb_hosted_zone_id
    evaluate_target_health = true
  }
}

data "terraform_remote_state" "route53_public" {
  backend = "s3"

  config = {
    region = var.terraform_state_aws_region
    bucket = var.terraform_state_s3_bucket
    key    = "_global/route53-public/terraform.tfstate"
  }
}

data "terraform_remote_state" "alb" {
  backend = "s3"

  config = {
    region = var.terraform_state_aws_region
    bucket = var.terraform_state_s3_bucket
    key    = "${var.aws_region}/${var.vpc_name}/networking/${var.is_internal_alb ? "alb-internal" : "alb-public"}/terraform.tfstate"
  }
}

variable "aws_region" {
  description = "The AWS region in which all resources will be created"
  default     = "us-east-1"
  type        = string
}

variable "vpc_name" {
  description = "The name of the environment in which all the resources should be deployed (e.g. stage, prod). This is typically the name of the VPC."
  type        = string
}

variable "is_internal_alb" {
  description = "If set to true, create only private DNS entries. We should be able to compute this from the ALB automatically, but can't, due to a Terraform limitation (https://goo.gl/gq5Qyk). Only used if var.create_route53_entry is true."
  type        = bool
  default     = false
}

variable "domain_name" {
  description = "The domain name for the DNS A record to add for this service (e.g. service.foo.com). Only used if var.create_route53_entry is true."
  default     = ""
  type        = string
}

variable "route53_hosted_zone_name" {
  description = "The name of the Route53 Hosted Zone where we will create a DNS record for this service (e.g. gruntwork-dev.io)"
  default     = "tabit-dev.com"
  type        = string
}

variable "terraform_state_aws_region" {
  description = "The AWS region of the S3 bucket used to store Terraform remote state"
  type        = string
}

variable "terraform_state_s3_bucket" {
  description = "The name of the S3 bucket used to store Terraform remote state"
  type        = string
}

variable "aws_account_id" {
  description = "The ID of the AWS Account in which to create resources."
  type        = string
}

variable "edge_entry_point" {
  description = "if true use edge as  entry point ot AWS ( ssl/termination ) and AWS internal infrastructure"
  type        = bool
  default     = false
}

variable "alb_weighted_numbers" {
  description = "Alb weighted number - use only number"
  type = list(object({
    weight  = number
  }))
  default = []
}

variable "edge_weighted_numbers" {
  description = "Edge weighted number - use only number"
  type = list(object({
    weight = number
  }))
  default = []
}

Debug Output

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
~ update in-place

Terraform will perform the following actions:

aws_route53_record.dns_record will be updated in-place

~ resource "aws_route53_record" "dns_record" {
fqdn = "53w.tabit-dev.com"
id = "Z189Y2MAF9B0HF_53w.tabit-dev.com_A_alb"
name = "53w.tabit-dev.com"
records = []

Plan: 0 to add, 1 to change, 1 to destroy.

Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.

Enter a value: yes

Panic Output

aws_route53_record.dns_record2[0]: Destroying... [id=Z189Y2MAF9B0HF_53w.tabit-dev.com_A_edge]
aws_route53_record.dns_record: Modifying... [id=Z189Y2MAF9B0HF_53w.tabit-dev.com_A_alb]
aws_route53_record.dns_record2[0]: Still destroying... [id=Z189Y2MAF9B0HF_53w.tabit-dev.com_A_edge, 10s elapsed]
aws_route53_record.dns_record2[0]: Still destroying... [id=Z189Y2MAF9B0HF_53w.tabit-dev.com_A_edge, 20s elapsed]
aws_route53_record.dns_record2[0]: Still destroying... [id=Z189Y2MAF9B0HF_53w.tabit-dev.com_A_edge, 30s elapsed]
aws_route53_record.dns_record2[0]: Destruction complete after 35s

Error: [ERR]: Error building changeset: InvalidChangeBatch: [RRSet with DNS name 53w.tabit-dev.com., type A cannot be created as other RRSets exist with the same name and type.] status code: 400, request id: a70bdcfa-d293-4618-bb2c-524f1d0648d1

on main.tf line 41, in resource "aws_route53_record" "dns_record":
41: resource "aws_route53_record" "dns_record" {

Releasing state lock. This may take a few moments...
[terragrunt] 2020/10/19 11:45:13 Hit multiple errors:
exit status 1

Expected Behavior

The aws_route53_record" "dns_record should convert to simple

Actual Behavior

Error: [ERR]: Error building changeset: InvalidChangeBatch: [RRSet with DNS name 53w.tabit-dev.com., type A cannot be created as other RRSets exist with the same name and type.]
status code: 400, request id: a70bdcfa-d293-4618-bb2c-524f1d0648d1

Steps to Reproduce

  1. terraform apply

Important Factoids

References

dekimsey commented 1 year ago

This occurred to me today, it seems to be that changing the routing policy needs to trigger a replacement of the resource and not a modification of the existing one.

Using:

$ terraform version 
Terraform v1.4.6
on darwin_arm64
+ provider registry.terraform.io/hashicorp/aws v5.7.0

Running:

$ terraform apply
  # aws_route53_record.us-primary will be updated in-place
  ~ resource "aws_route53_record" "us-primary" {
        id                               = "IDHERE_example.com_A_example_us_primary"
        name                             = "example.com"
        # (7 unchanged attributes hidden)

      - failover_routing_policy {
          - type = "PRIMARY" -> null
        }

      + latency_routing_policy {
          + region = "us-east-1"
        }

        # (1 unchanged block hidden)
    }

Emits the error:

 Error: creating Route 53 Record: InvalidChangeBatch: [RRSet with DNS name example.com., type A, SetIdentifier example_us_primary, and Region Name=us-east-1 cannot be created because a non-latency RRSet with the same name and type already exists.]
│       status code: 400, request id: 9b8d701b-a46b-4075-bb7f-289afce9025c
│ 
│   with aws_route53_record.us-primary,
│   on route53.us.tf line 1, in resource "aws_route53_record" "us-primary":
│    1: resource "aws_route53_record" "us-primary" {
│