For context, see #8099, where I stumbled across @apparentlymart 's call for use cases. This bit in particular inspired me, as this is exactly the functionality I'm looking for:
It might work out conceptually simpler to generalize the triggers idea from null_resource or keepers from the random provider, so that it can be used on any resource
Generically speaking, I'd like to force a new resource when the contents of a file it depends on changes.
More specifically, say I have a compute instance resource with a Chef provisioner using a Policyfile to define its cookbooks, run-list, etc. In a test workflow I'd like to detect changes to policy JSON and force re-create the compute instances to ensure the new policy is effective on a clean slate (without disrupting other resources that aren't affected by the policy change).
resource "compute_instance" "my_policy" {
...
provisioner "chef" {
...
use_policyfile = true
policy_group = "staging"
policy_name = "my_policy"
}
lifecycle {
replace_on_change {
policyfile = "${file("policies/my_policy.rb")}"
}
}
}
Consider another workflow, which is probably more common, where a simple shell script is sufficient for provisioning a compute instance and it is desirable to start with a fresh instance anytime the provisioning logic changes:
resource "compute_instance" "foo" {
...
provisioner "file" {
source = "setup.sh"
destination = "/tmp/setup.sh"
}
provisioner "remote-exec" {
inline = [
"chmod +x /tmp/setup.sh",
"/tmp/setup.sh"
]
}
lifecycle {
replace_on_change {
policyfile = "${file("setup.sh")}"
}
}
}
Currently, if the contents of setup.sh
change, Terraform has no visibility into this and just leaves the instance be. Allowing users to hash the contents would make for easy re-provisioning without the need to care about the idempotence issues of just re-running the provisioner as discussed in #745 and elsewhere (assuming one is willing to take the hit on re-creating the resource from scratch).
Retagging as enhancement. A good idea though.
I could really use this too - my use case is similar but related to GCP XPN (cross project networking) policy bindings (JSON). XPN subnet policy bindings are how XPN (host) subnetworks are shared to a project - right now, in the beta at least, you associate a service project with an XPN Host project with a single gcloud command, however, each subnetwork you want users in that service project to be able to use needs to be bound with a gcloud command and a JSON policy document (another gcloud command per network per binding).
Until that gets sorted out, we're binding all networks to each new service project's users' groups' as they come online - however, today that means I have to taint some 42 null_resource objects to get the gcloud command to run again - I'd much rather tag them with a dependency on a policy file like the above. E.g.:
resource "null_resource" "subnetwork-association-one-eleventy-one-one-bang1" {
provisioner "local-exec" {
command = "yes | gcloud beta compute networks subnets set-iam-policy one-eleventy-one-one-bang1 subnet-policy.json --region ${var.gcp-us-west} --project my-xpn-host-project"
}
}
where subnet-policy.json is the file being updated each time a new service project is added:
{
"bindings": [
{
"members": [
"group:[email protected]",
"group:[email protected]",
"serviceAccount:[email protected]",
"serviceAccount:[email protected]",
"serviceAccount:[email protected]",
"group:[email protected]",
"group:[email protected]",
"serviceAccount:[email protected]",
"serviceAccount:[email protected]",
"serviceAccount:[email protected]"
],
"role": "roles/compute.networkUser"
}
],
}
@allandrick possibly I'm not understanding your use-case properly, but I think you can achieve what you need today using the triggers
attribute:
resource "null_resource" "subnetwork-association-one-eleventy-one-one-bang1" {
triggers = {
policy_sha1 = "${sha1(file("subnet-policy.json"))}"
}
provisioner "local-exec" {
command = "yes | gcloud beta compute networks subnets set-iam-policy one-eleventy-one-one-bang1 subnet-policy.json --region ${var.gcp-us-west} --project my-xpn-host-project"
}
}
This issue is asking essentially for this triggers
mechanism to be generalized to all resources, but since you happen to be using null_resource
you can use the already-existing version of this built in to that resource.
@apparentlymart thank you very much - that does the trick nicely!
I could have also used a data template_file resource with or without vars to pick up any changes that way... but your way is much more elegant!
Regards,
Leigh
Most helpful comment
@allandrick possibly I'm not understanding your use-case properly, but I think you can achieve what you need today using the
triggers
attribute:This issue is asking essentially for this
triggers
mechanism to be generalized to all resources, but since you happen to be usingnull_resource
you can use the already-existing version of this built in to that resource.