I have a schema attribute,
"volumes": {
Type: schema.TypeSet,
Optional: true,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
Description: "List of volume ids",
},
How to handle changes that have been made outside terraform or in some other resources ?
at start ,
volumes = [ “vol1”, “vol2” ]
then I created new volumes and attached , and in background volumes became
volumes = [ “vol1”, “vol2”, “vol3” ]
On plan, my provider shows an update.
Note: Objects have changed outside of Terraform
Terraform detected the following changes made outside of Terraform since the last "terraform apply":
~ volumes = [
+ "vol3",
# (1 unchanged element hidden)
]
Unless you have made equivalent changes to your configuration, or ignored the relevant attributes using ignore_changes, the following plan may include actions to undo or respond to these changes.
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
~ update in-place
~ volumes = [
- "vol3",
# (1 unchanged element hidden)
]
# (18 unchanged attributes hidden)
# (3 unchanged blocks hidden)
}
Plan: 0 to add, 1 to change, 0 to destroy.
In first block, it shows a change has been made with a (+) sign.
In second block, terraform is showing an update.
Please suggest
@jbardin @apparentlymart Is there a way to achieve this ?
Hi @ramuklawjju,
If I understand the question correctly, the provider cannot contradict what is defined in the configuration. The goal of Terraform is to make the resource match the configuration, and external changes will be reverted when they diverge.
If you want to define an initial value in the configuration, yet allow external changes later on, then the user will have to use ignore_changes
to prevent the configuration from making changes to the attribute after the first apply.
In addition to @jbardin’s note, I wanted to point out that Terraform Core always sends the entire prior state to the “read” operation for a provider so that in some complex situations like these the provider can potentially react to what was defined before in order to decide how to recognize changes made outside of Terraform.
Without knowing more about the system you are modelling I don’t know if this applies here, but if this is a situation where there’s a mixture of volumes defined as a part of a VM and other volumes attached separately later, then you could potentially make use of what I described above to try to distinguish between the subset of volumes this resource is managing vs. volumes that arrived later, using some custom logic in the Read
function.
For example, if the prior state only shows ["vol1", "vol2"]
then your Read
logic could potentially look up those volumes in particular to make sure that they still exist and are still attached, and then return only the subset of the previous volumes that are still present.
If you find that vol2
became unattached, for example, you could return ["vol1"]
to reflect that the remote system no longer matches the original definition. But you’d ignore the addition of any other volumes, assuming that they are managed by some other resource elsewhere, and thus not include them in the result.
Within the Terraform SDK Read
pattern you can use d.Get("volumes")
prior to calling d.Set("volumes", ...)
in order to see the prior state value, and then react to that prior value in any way you like to customize the construction of the value you’ll eventually pass to d.Set
.
This sort of approach wouldn’t be appropriate for all situations, because it effectively prevents Terraform’s refresh phase from detecting the addition of new volumes from outside, but if adding new volumes later is part of the intended use of this resource type then this would be one way to model that.