I am attempting to use the terraform-provider-http to fill in some gaps within the Heroku Terraform provider. This data item allows for an HTTP POST against an API endpoint. I would like to restrict the creation of this data resource to only fire once. I don’t want that POST to ever be fired again.
With a standard resource that follows Terraform lifecycle rules, this is easy:
lifecycle {
ignore_changes = all
}
However with a data resource, this is not possible.
Is there a way to only fire a data resource when that resource doesn’t already exist in state?
One of the things I am using this to do is to initiate an API call to seed the database. This CANNOT be done more than once; once the initial setup and configuration of the database is done, this should never be done again.
No, this is not possible. Although I wish Terraform posessed the ability to re-use data source data from the state, it doesn’t, and the presence of data source data in the state file is only used for visualizing the results or debugging.
I think I have a solution that doesn’t require the use of a null_resource or building a custom provider. I have the following inside each of the data resources I want to run once:
count = var.first_apply ? 1 : 0
Then that variable is defined with a default of false.
For the first run, I explicitly set the variable to true in a tfvars file; then after that apply, I remove the variable from the tfvars file and the default takes over. It is not pretty, but I think it will accomplish the goals I have.
In general, I’m not a fan of the count keyword, but in this case, it’s a transparent/obvious way to pull this off. I would be curious if someone has a better idea - I’m all ears.
Something to consider here is that the intent of a data source is to only read data. The dependency resolution and evaluation in Terraform counts on the fact that a data source cannot have any side effects. Data sources implemented with side effects can cause other confusing situations where it takes multiple applies to converge on a stable state (if it reaches that point at all), or the apply fails entirely when the final state is not valid for the given plan. If side effects are required, then the action should be accomplished with a managed resource.
Building on this thread and the points raised by @johnson.chris, I wanted to share that I’ve submitted PR #558 to address Issue #300, which is currently the most upvoted issue in the terraform-provider-http repository.
The PR introduces support for managing HTTP interactions via a resource, rather than relying solely on the data source, while maintaining a clear separation from the existing data source. This aligns with Terraform’s lifecycle model and avoids repeated HTTP requests during frequent plan/apply cycles—especially useful for POST operations like database seeding, where idempotency is critical.
I’ve tested the implementation locally and it’s working well. It would be great if this could be prioritized, as we’d prefer not to rely on null_resource workarounds, which introduce additional complexity and overhead.