Hello - I’m working on my first terraform project and am hitting a snag. I’d appreciate any advice or guidance folks could offer!
Thanks in Advance!
Background: Goal and Problem
Goal:
I am looking for a way to create a terraform resource only when a real-world resource of the same name doesn’t already exist.
My basic setup includes:
terraform version
Terraform v1.5.7
on darwin_amd64
+ provider registry.terraform.io/hashicorp/http v3.4.0
- a data source to get me a list of extant items (Unfortunately the provider I’m working with doesn’t have a data source I can check, so I’m using the http provider’s data source to return information about the items from an API endpoint)
- a corresponding
local
that creates a list of item names from the response body - a resource with the
for_each
meta-argument usessetsubtract
to compute a set of items to create by checking for their existence in thelocal
list
An initial terraform apply
works as expected to correctly identify existing item names, and create the resource if none exist with the same name.
Problem:
A subsequent terraform apply
will delete the just-created resource
This appears to be happening due to subsequent terraform plan
and terraform apply
runs not refreshing the content of the data source (even when using refresh-only
). Interestingly, running terraform refresh
does update the content of the data source to include the just-created item name. This appears to cause my for_each
meta-argument to produce a set that never includes the just-created item name, which triggers that resource’s destruction.
The common workaround of just import these existing items into terraform doesn’t meet my project’s requirement for terraform-managed resources to coexist with resources created outside of terraform (without taking over their management, which introduces the risk of their accidental destruction).
What I’ve tried
data.tf
data "http" "rules" {
url = "${local.baseurl}/api/v1/rules"
}
locals {
rules = toset([for i in jsondecode(data.http.rules.response_body).data : i.name])
}
main.tf
# current config
resource "provider_rule" "my_rule" {
for_each = setsubtract(["My Rule"], local.rules)
name = "My Rule"
}
# also tried
resource "provider_rule" "my_rule" {
for_each = contains(local.rules, "My Rule") ? toset([]) : toset(["rule"])
name = "My Rule"
}
outputs.tf
output "existing_rules" {
value = local.rules
}
terraform output
existing_rules = toset([
"My Rule",
"foo bar",
])
subsequent terraform plan
# module.provider.rule.my_rule["My Rule"] will be destroyed
# (because key ["My Rule"] is not in for_each map)
- resource "rule" "my_rule" {
- enabled = true -> null
- id = "0000000000014A51" -> null
- name = "My Rule" -> null
}
Plan: 0 to add, 0 to change, 1 to destroy.