Closed ajax-mykhailo-oleksiuk closed 1 year ago
Voting for Prioritization
Volunteering to Work on This Issue
hi 👋 per the issue template, we don't accept reproduction cases that are using modules or dynamic expressions. for someone to triage this further, we need a reproduction case that only has the provider code; not the potential of logic bugs with client side expressions.
additionally, the error message you got indicates that you are attempting to overwrite but not finding a single record to match on and overwrite so it is bailing out. I suspect this is either an issue with your variables or the way your module is built.
Hi @jacobbednarz
I've been able to reproduce it without public module. Here is a code:
locals {
domain = "*.ajax.systems"
# output for this local variable validation_domains is
#validation_domains = tolist([
# {
# "domain_name" = "ajax.systems"
# "resource_record_name" = "_c5ff38ec8554d7a1bfb88decc1f2440c.ajax.systems."
# "resource_record_type" = "CNAME"
# "resource_record_value" = "_590e5921488d12cc15327231bfe08836.fpgkgnzppq.acm-validations.aws."
# },
#])
validation_domains = distinct(
[for k, v in aws_acm_certificate.this.domain_validation_options : merge(
tomap(v), { domain_name = replace(v.domain_name, "*.", "") }
)]
)
}
resource "aws_acm_certificate" "this" {
domain_name = local.domain
validation_method = "DNS"
options {
certificate_transparency_logging_preference = "ENABLED"
}
lifecycle {
create_before_destroy = true
}
}
resource "aws_acm_certificate_validation" "this" {
certificate_arn = aws_acm_certificate.this.arn
validation_record_fqdns = [cloudflare_record.this.hostname]
}
# -------------------------------------
# Certificate validation via Cloudflare
# -------------------------------------
resource "cloudflare_record" "this" {
zone_id = data.cloudflare_zone.this.id
name = local.validation_domains.0.resource_record_name
type = local.validation_domains.0.resource_record_type
value = trimsuffix(local.validation_domains.0.resource_record_value, ".")
ttl = 60
proxied = false
allow_overwrite = true
}
But getting the same error: attempted to override existing record however didn't find an exact match
Also, I'm little bit confused because I see in debug messages that cloudflare provider under the hood finds existing record correctly
2023-05-03T21:53:51.138+0300 [DEBUG] provider.terraform-provider-cloudflare_v4.5.0: {"result":null,"success":false,"errors":[{"code":81053,"message":"An A, AAAA, or CNAME record with that host already exists. For more details, refer to \u003chttps://developers.cloudflare.com/dns/manage-dns-records/troubleshooting/records-with-same-name/\u003e."}],"messages":[]}
2023-05-03T21:53:51.138+0300 [DEBUG] provider.terraform-provider-cloudflare_v4.5.0: Cloudflare Record already exists however we are overwriting it: tf_req_id=2067d3bc-6119-ee1b-0a92-b5f39e539176 @caller=github.com/cloudflare/terraform-provider-cloudflare/internal/sdkv2provider/resource_cloudflare_record.go:142 tf_provider_addr=registry.terraform.io/cloudflare/cloudflare tf_rpc=ApplyResourceChange @module=cloudflare tf_mux_provider=tf5to6server.v5tov6Server tf_resource_type=cloudflare_record timestamp=2023-05-03T21:53:51.138+0300
2023-05-03T21:53:51.139+0300 [DEBUG] provider.terraform-provider-cloudflare_v4.5.0: 2023/05/03 21:53:51
2023-05-03T21:53:51.139+0300 [DEBUG] provider.terraform-provider-cloudflare_v4.5.0: GET /client/v4/zones/176b2792aab9d7de9f322bd71409307b HTTP/1.1
2023-05-03T21:53:51.139+0300 [DEBUG] provider.terraform-provider-cloudflare_v4.5.0: Host: api.cloudflare.com
2023-05-03T21:53:51.139+0300 [DEBUG] provider.terraform-provider-cloudflare_v4.5.0: User-Agent: terraform/1.3.7 terraform-plugin-sdk/2.10.1 terraform-provider-cloudflare/4.5.0
2023-05-03T21:53:51.139+0300 [DEBUG] provider.terraform-provider-cloudflare_v4.5.0: Authorization: Bearer [redacted]
2023-05-03T21:53:51.141+0300 [DEBUG] provider.terraform-provider-cloudflare_v4.5.0: Content-Type: application/json
2023-05-03T21:53:51.141+0300 [DEBUG] provider.terraform-provider-cloudflare_v4.5.0: Accept-Encoding: gzip
2023-05-03T21:53:51.141+0300 [DEBUG] provider.terraform-provider-cloudflare_v4.5.0:
cloudflare_record.this: Still creating... [30s elapsed]
2023-05-03T21:53:51.586+0300 [DEBUG] provider.terraform-provider-cloudflare_v4.5.0: 2023/05/03 21:53:51 [WARN] WaitForState timeout after 30s
2023-05-03T21:53:51.586+0300 [DEBUG] provider.terraform-provider-cloudflare_v4.5.0: 2023/05/03 21:53:51 [WARN] WaitForState starting 30s refresh grace period
2023-05-03T21:53:51.587+0300 [DEBUG] provider.terraform-provider-cloudflare_v4.5.0: 2023/05/03 21:53:51 [TRACE] Waiting 10s before next try
2023-05-03T21:53:51.587+0300 [DEBUG] provider.terraform-provider-cloudflare_v4.5.0: 2023/05/03 21:53:51 [ERROR] Context cancelation detected, abandoning grace period
-- and here says about mismatch
2023-05-03T21:53:51.588+0300 [ERROR] provider.terraform-provider-cloudflare_v4.5.0: Response contains error diagnostic: diagnostic_detail= diagnostic_severity=ERROR tf_req_id=2067d3bc-6119-ee1b-0a92-b5f39e539176 tf_rpc=ApplyResourceChange @caller=github.com/hashicorp/terraform-plugin-go@v0.15.0/tfprotov6/internal/diag/diagnostics.go:55 diagnostic_summary="attempted to override existing record however didn't find an exact match" tf_proto_version=6.3 tf_provider_addr=registry.terraform.io/cloudflare/cloudflare tf_resource_type=cloudflare_record @module=sdk.proto timestamp=2023-05-03T21:53:51.586+0300
2023-05-03T21:53:51.588+0300 [ERROR] vertex "cloudflare_record.this" error: attempted to override existing record however didn't find an exact match
and then says it's didn't find an exact match
that still relies on loops and accessing indexes directly. you should be able to build a reproduction case with just two cloudflare_record
resources with static values. the first without a allow_overwrite
, the second with it and a depends_on
to ensure correct ordering.
@jacobbednarz sure
I've cleaned up all code related to AWS.
Requested certificate in AWS ACM and here is its properties:
And the complete example of code that still have the issue:
terraform {
required_version = "1.3.7"
required_providers {
cloudflare = {
source = "cloudflare/cloudflare"
version = "4.5.0"
}
}
}
provider "cloudflare" {}
data "cloudflare_zone" "this" { name = trimprefix(local.domain, "*.") }
locals { domain = "*.ajax.systems"
record_name = "_c5ff38ec8554d7a1bfb88decc1f2440c.ajax.systems." record_type = "CNAME" record_value = "_590e5921488d12cc15327231bfe08836.fpgkgnzppq.acm-validations.aws." }
resource "cloudflare_record" "first" { zone_id = data.cloudflare_zone.this.id name = local.record_name type = local.record_type value = local.record_value ttl = 60 proxied = false
allow_overwrite = false }
resource "cloudflare_record" "second" { zone_id = data.cloudflare_zone.this.id name = local.record_name type = local.record_type value = local.record_value ttl = 60 proxied = false
allow_overwrite = true
depends_on = [cloudflare_record.first] }
Result:
╷ │ Error: attempted to override existing record however didn't find an exact match │ │ with cloudflare_record.second, │ on certificate.tf line 37, in resource "cloudflare_record" "second": │ 37: resource "cloudflare_record" "second" { │ ╵
5. And this is debug logs for this code - https://gist.github.com/ajax-mykhailo-oleksiuk/e6c6d6d83d75721ce3e4c2871c468be7
As a result, the first record is created successfully and the second one fails.
I can verify this behavior as well. However if you import the record into tfstate it will work just fine. At least for me.
the value you are using won't work as if the value isn't @
or the root domain, we combine the name
with the zone name to build the value - https://github.com/cloudflare/terraform-provider-cloudflare/blob/master/internal/sdkv2provider/resource_cloudflare_record.go#L144-L154.
to make this work, the name
value should only be _c5ff38ec8554d7a1bfb88decc1f2440c
.
I'm facing a same issue. I've added two records in CF, name: "example", ip addresses "1.2.3.4" and "4.3.2.1" (for test purposes)
terraform {
required_version = "1.5.2"
required_providers {
cloudflare = {
source = "cloudflare/cloudflare"
version = "~> 4.10"
}
}
}
resource "cloudflare_record" "example1" {
zone_id = data.cloudflare_zone.default.id
name = "example"
type = "A"
value = "1.2.3.4"
ttl = 1
proxied = true
allow_overwrite = true
}
resource "cloudflare_record" "example2" {
zone_id = data.cloudflare_zone.default.id
name = "example"
type = "A"
value = "4.3.2.1"
ttl = 1
proxied = true
allow_overwrite = true
}
data "cloudflare_zone" "default" {
name = var.zone
}
After terraform apply
i get error:
cloudflare_record.example2: Creating...
cloudflare_record.example1: Creating...
cloudflare_record.example2: Still creating... [10s elapsed]
cloudflare_record.example1: Still creating... [10s elapsed]
cloudflare_record.example1: Still creating... [20s elapsed]
cloudflare_record.example2: Still creating... [20s elapsed]
cloudflare_record.example1: Still creating... [30s elapsed]
cloudflare_record.example2: Still creating... [30s elapsed]
╷
│ Error: attempted to override existing record however didn't find an exact match
│
│ with cloudflare_record.example1,
│ on test.tf line 11, in resource "cloudflare_record" "example1":
│ 11: resource "cloudflare_record" "example1" {
│
╵
╷
│ Error: attempted to override existing record however didn't find an exact match
│
│ with cloudflare_record.example2,
│ on test.tf line 21, in resource "cloudflare_record" "example2":
│ 21: resource "cloudflare_record" "example2" {
│
╵
And if I change allow_overwrite = false
I'm getting error:
cloudflare_record.example1: Creating...
cloudflare_record.example2: Creating...
cloudflare_record.example1: Still creating... [10s elapsed]
cloudflare_record.example2: Still creating... [10s elapsed]
cloudflare_record.example2: Still creating... [20s elapsed]
cloudflare_record.example1: Still creating... [20s elapsed]
cloudflare_record.example2: Still creating... [30s elapsed]
cloudflare_record.example1: Still creating... [30s elapsed]
╷
│ Error: expected DNS record to not already be present but already exists
│
│ with cloudflare_record.example1,
│ on test.tf line 11, in resource "cloudflare_record" "example1":
│ 11: resource "cloudflare_record" "example1" {
│
╵
╷
│ Error: expected DNS record to not already be present but already exists
│
│ with cloudflare_record.example2,
│ on test.tf line 21, in resource "cloudflare_record" "example2":
│ 21: resource "cloudflare_record" "example2" {
│
╵
Help me please @jacobbednarz @ajax-mykhailo-oleksiuk What is the problem in my case?
same, allow_overwrite
doesn't work...
resource "cloudflare_record" "cert_validation" {
for_each = {
for dvo in aws_acm_certificate.this.domain_validation_options : dvo.domain_name => {
name = dvo.resource_record_name
record = dvo.resource_record_value
type = dvo.resource_record_type
}
}
zone_id = var.cloudflare_zone_id
name = each.value.name
value = each.value.record
type = each.value.type
ttl = 60
allow_overwrite = true
proxied = false
}
loops are not the reason, because it works correctly for the first run, creates the record, and then on subsequent run it fails - idempotency of the provider doesn't work, it should either fail both times or pass both times 🤷♂️
I have the same issue as the OP.
In my case I create a certificate in AWS that allows:
example.com
*.example.com
AWS creates validation records that need to be inserted into Cloudflare. However both validation records are exactly the same and I cannot define two exact same records, so I need to use allow_overwrite = true
.
However, in terraform I then receive Error: attempted to override existing record however didn't find an exact match
for the second validation record.
The reason is that Cloudflare strips off the .
from the ends of the name and value of the validation records, so terrafom (Cloudflare??) cannot find the record to overwrite.
So to workaround this I trim off the .
before writing the record, this then results in a different error when deleting the record Error: error deleting Cloudflare Record: Record does not exist. (81044)
. Terraform says it cannot find the record, but still deletes it on the first apply, and a second apply then runs with any error.
I appreciate the Cloudflare provider cannot account for all types of input coming from other resources, however this seems to be a specific issue in the Cloudflare provider. It should handle the above scenario in some shape or form, either allowing the overwrite to work, or allowing the delete the work when managing AWS certificate validation records. I guess this is a very common task people need to do so the provider should incorporate whatever is required to make it work.
I'm facing a same issue. I've added two records in CF, name: "example", ip addresses "1.2.3.4" and "4.3.2.1" (for test purposes)
terraform { required_version = "1.5.2" required_providers { cloudflare = { source = "cloudflare/cloudflare" version = "~> 4.10" } } } resource "cloudflare_record" "example1" { zone_id = data.cloudflare_zone.default.id name = "example" type = "A" value = "1.2.3.4" ttl = 1 proxied = true allow_overwrite = true } resource "cloudflare_record" "example2" { zone_id = data.cloudflare_zone.default.id name = "example" type = "A" value = "4.3.2.1" ttl = 1 proxied = true allow_overwrite = true } data "cloudflare_zone" "default" { name = var.zone }
After
terraform apply
i get error:cloudflare_record.example2: Creating... cloudflare_record.example1: Creating... cloudflare_record.example2: Still creating... [10s elapsed] cloudflare_record.example1: Still creating... [10s elapsed] cloudflare_record.example1: Still creating... [20s elapsed] cloudflare_record.example2: Still creating... [20s elapsed] cloudflare_record.example1: Still creating... [30s elapsed] cloudflare_record.example2: Still creating... [30s elapsed] ╷ │ Error: attempted to override existing record however didn't find an exact match │ │ with cloudflare_record.example1, │ on test.tf line 11, in resource "cloudflare_record" "example1": │ 11: resource "cloudflare_record" "example1" { │ ╵ ╷ │ Error: attempted to override existing record however didn't find an exact match │ │ with cloudflare_record.example2, │ on test.tf line 21, in resource "cloudflare_record" "example2": │ 21: resource "cloudflare_record" "example2" { │ ╵
And if I change
allow_overwrite = false
I'm getting error:cloudflare_record.example1: Creating... cloudflare_record.example2: Creating... cloudflare_record.example1: Still creating... [10s elapsed] cloudflare_record.example2: Still creating... [10s elapsed] cloudflare_record.example2: Still creating... [20s elapsed] cloudflare_record.example1: Still creating... [20s elapsed] cloudflare_record.example2: Still creating... [30s elapsed] cloudflare_record.example1: Still creating... [30s elapsed] ╷ │ Error: expected DNS record to not already be present but already exists │ │ with cloudflare_record.example1, │ on test.tf line 11, in resource "cloudflare_record" "example1": │ 11: resource "cloudflare_record" "example1" { │ ╵ ╷ │ Error: expected DNS record to not already be present but already exists │ │ with cloudflare_record.example2, │ on test.tf line 21, in resource "cloudflare_record" "example2": │ 21: resource "cloudflare_record" "example2" { │ ╵
Help me please @jacobbednarz @ajax-mykhailo-oleksiuk What is the problem in my case?
Your example is wrong. allow_overwrite
allows you to overwrite a record that is exactly the same as a current record. In your example the value is different so it is not supposed to overwrite it.
All you need to do is remove the second resource and just update the first resource with the value you want.
allow_overwrite
is designed to be used where another resource is creating duplicate records, such as AWS certificate validation records, and those duplicate records are being passed to Cloudflare.
As @jacobbednarz alluded to in https://github.com/cloudflare/terraform-provider-cloudflare/issues/2407#issuecomment-1537593487, if you trim the zone's name from the record's name
it does work, so the correct workaround for making domain validation records from an AWS certificate request is:
data "cloudflare_zone" "default" {
name = var.zone
}
resource "cloudflare_record" "cert_validation" {
for_each = {
for dvo in aws_acm_certificate.this.domain_validation_options : dvo.domain_name => {
name = dvo.resource_record_name
record = dvo.resource_record_value
type = dvo.resource_record_type
}
}
zone_id = data.cloudflare_zone.default.zone_id
name = trimsuffix(each.value.name, ".${data.cloudflare_zone.default.name}.")
value = each.value.record
type = each.value.type
allow_overwrite = true
}
Thank you @waddles this is exactly what I was looking for. A recent update to our provider introduced this error message we had never seen before and caused quite a bit of chaos.
If you're reading this because you're using cdktf and tried to Token.as_list(records_iterator.pluck_property("name"))
use the hostname
property instead and aws_acm_certificate_validation
won't complain anymore, since cloudflare_record's hostname
== route53_record's fqdn
.
Confirmation
Terraform and Cloudflare provider version
Affected resource(s)
cloudflare_record
Terraform configuration files
Link to debug output
https://gist.github.com/ajax-mykhailo-oleksiuk/36b1b8b106a365b03e0dabd8146f6f45
Panic output
No response
Expected output
Actual output
Steps to reproduce
eu-west-1
) This step completes successfully because Cloudflare doesn't have cname record for a new certificate.us-east-1
). This step fails with the error above. (Difference between codebase for different region in aws provider only)Additional factoids
eu-west-1
to codebase inus-east-1
and hoped to have a workaround for this but getting "recreate" stage in codebase forus-east-1
:attempted to override existing record however didn't find an exact match
. But when I set (for test purposes)allow_overwrite = false
I'm getting error showing that match was successful:References
No response