Delete a resource once another resource attribute updated to a certain value

This is really related to the example shown on: plantimestamp - Functions - Configuration Language | Terraform | HashiCorp Developer

Let’s take I have a tls_certificate resource. I need to create a verification DNS resource. Once the certificate is valid then the verification DNS isn’t needed. Let’s take for example the following pseudo code:

resource "cert" "mycert"{
}

resource "validation" "certvalid"{
count = cert.mycert.status == "VALID" ? 0 : 1
}

The issue is cert.mycert.status cannot be determined until apply and bring the error Alternatively, you could use the -target planning option to first apply only the resources that the for_each value depends on, and then apply a second time to fully converge. Unfortunately in my automation pipeline I can’t do --target

Is there a clever method to workaround this problem?

I’ve also tried using time_static by considering after X many hours we can delete the validation resource but it got the same issue.

I understand your problem, but when you running a plan, virtual fields like status of the cert (fields when can determinated running a query in data source) cannot be determinated in first run, you need to run target to get value and run again.

Another approach is using data source and filtering by status and check if exists, and link the condition.

But the cert doesn’t exist in the first place so it wouldn’t be possible to data.

Is there a way to default a data resource if data isn’t found?

try(data "cert" "mycert"{
  name = "mycert"
},
{
  name="ABC"
  status="VALID"
})
 

Obviously the above doesn’t work but something in this spirit

I think litte different, using for_each instead count or using “try” in count statement.
count = try ( ... , 0)

Basing a conditional of a data source cannot work because the resource you wish to look up won’t yet exist.

Terraform doesn’t really have a way to express “I want this resource temporarily”. The configuration declares the desired state, and given a stable infrastructure, that desired state should always remain the same with a given config. A configuration which produces a change immediately after a full apply is considered a bug, whether it be in the config, Terraform, or the provider.

The “validation” you want to do here isn’t really a resource under Terraform’s normal definition of a managed resource, it’s more of a series of actions you want to take. You created the cert, and the steps to verify it are create a dns entry, wait for verification, then delete the dns entry. That would have to be some procedural code done outside of a single Terraform apply.

A dns entry is rather inconsequential, is that something that can just be left as an artifact of the cert creation until that cert is replaced or removed?

Sorry my error, @jbardin is right about data source conditionals, my suggestion cannot work because if the resource doesnt exists, terraform report error.

Other approach is separate blocks in 2 separate “folders” and use remote state/data-source to share condition.

I understand the reasoning. Now terraform is made of many workarounds, I guess the pre-target is one of them, I was trying to find if there was another one.

To come back to my previous comment, is there any plan to support a data element with default value when not found? It would solve quite a lot of cases (including this one) and I don’t think it’s out of the line from what terraform does.

1 Like

What a data resource does (within the bounds of the provider protocol) is up to the provider. Many data sources can search for zero for more resource instances, but it’s up to the provider to incorporate such a resource.

The common motivation to use a data resource in this manner is to conditionally create some other resource, resulting in an unstable configuration, so users typically end up realizing that is not what they actually want (often resulting in plans which perpetually flip-flop between create and destroy). It seems here however that you are looking for a configuration which does not remain stable after apply, and subsequent plans can continue to change the resulting infrastructure. That goal is counter to Terraform’s intended design, so there is inherently going to be some friction or workarounds involved to achieve it.

If you want the validation DNS entry to be removed from the configuration, that is a followup action that will need to be taken. In most cases something like that validation DNS entry is just left alone, since having it under Terraform management ensures it’s not going to be forgotten about, and can be replaced when the associated cert is replaced. Otherwise accomplishing this with a single static configuration will require finding or creating a resource (a custom data resource would probably be the most direct option) which can return a consistently known value during plan to base the validation creation off from.

What a data resource does (within the bounds of the provider protocol) is up to the provider. Many data sources can search for zero for more resource instances, but it’s up to the provider to incorporate such a resource.

The edge case I’m trying to pin point is when searching for 1 resource but the resource isn’t there. All providers I know just fails and there’s no failsafe option (default object value). But you’re right this a behaviour decided by the provider. As I’m not a well experienced provider developer would it be possible for the provider to offer a “default” object in case of nothing found?

For example:

data "aws_ecr_image" "myimage" {
    repository_name = "name"
    registry_id = "XYZ"
    most_recent = true

  default = {
        id = "sha256:dummy"
        image_digest = "sha256:dummy"
        image_pushed_at = 123
        image_size_in_bytes = 123
        image_tags = [
            "latest",
        ]
        most_recent = true
        registry_id = "XYZ"
        repository_name = "name"
    }
}

and in case the repo doesn’t have any image it would return an object:

{
        id = "sha256:dummy"
        image_digest = "sha256:dummy"
        image_pushed_at = 123
        image_size_in_bytes = 123
        image_tags = [
            "latest",
        ]
        most_recent = true
        registry_id = "XYZ"
        repository_name = "name"
}

I’m asking in a question of “is it feasible” not “should we do it”.

Yup, the provider can return anything it wants! If it wants to return some sentinel value that indicates nothing was found, that is fine too. You’re right that most providers don’t do this, because it lends itself to creating configurations which don’t work correctly, a data resource is intended to represent an existing resource which just isn’t managed under the current configuration.

Many providers do have some “plural” data sources which can effectively do the same thing, by taking a query of some sort and returning a list of zero or more instances. That of course requires some extra work by the provider, so they are not always implemented on top of the normal managed/data resource pair.

While I’ll immediately concede that this isn’t really what the feature is designed for, and would come with some potentially-significant caveats, this got me thinking about the possibility of an ephemeral resource type representing each of these kinds of objects that sometimes need to be created only temporarily to prove that a caller of one API has access to modify something through another API.

For example:

  • A temporary DNS record in a DNS zone
  • A temporary static file in something that can be served as a website, like an S3 bucket

The most significant caveat is that although the ephemeral resource type’s “close” action could make a best effort to destroy the object once it’s no longer needed, it would have no recourse if that deletion fails for some reason, and “close” would not get called at all if Terraform crashes completely. (There is no record of ephemeral resources in the state by design, so if the “close” action fails to destroy it then it’ll just get immediately forgotten by Terraform. Ephemeral resources are more appropriate for objects that can eventually clean themselves up if abandoned, such as a time-limited session token.)

I expect that caveat would make the authors of commonly-used, general-purpose providers reluctant to implement ephemeral resource types like this, but that doesn’t mean that a sufficiently-motivated person couldn’t make a specialized provider that is designed for people who have this need and are willing to accept the risk that the verification objects might fail to destroy.

ephemeral "something_dns_record" "example" {
  # This is presumably needed only during the apply phase,
  # when the TLS certificate creation request will be sent.
  count = terraform.applying ? 1 : 0

  type = "TXT"
  name = "example.com"
  # etc, etc
}

resource "somethingelse_tls_certificate" "example" {
  # depends_on to make sure Terraform understands that the
  # ephemeral resource instance must remain open until
  # actions on this resource are complete.
  depends_on = [ephemeral.something_dns_record.example]

  # etc, etc
}

Assuming that both of these resource types are correctly implemented and nothing else goes wrong dynamically, I’d expect this to achieve the intended order of operations:

  • “Open” ephemeral.something_dns_record.example, causing the DNS record to be created.
  • Create somethingelse_tls_certificate.example, presumably causing the remote API to check whether the DNS record has been created.
  • “Close” ephemeral.something_dns_record.example, causing the DNS record to be destroyed.

DNS in particular of course raises some additional questions around caching, but I would hope that a system that is making DNS queries for the purposes of verifying ownership of a domain using a transient DNS record would be designed to bypass caching layers and go directly to the primary nameserver for the domain. :man_shrugging: