terraform-plugin-framework
terraform-plugin-framework copied to clipboard
Get update attribute in Update method and throw error when attribute can not be updated
Module version
github.com/hashicorp/terraform-plugin-framework v0.11.1
Use-cases
I am trying to implement Update in a resource, but find something complex for me:
- Some attributes is needed when create, but they can not be updated. How can I throw errors when they are changed? now, I need to compare the plan and state and throw errors myself for the attributes can not be changed
- Can I get the attributes that are updated? now, I also compare the plan and state to find out the changed attributes
Attempted Solutions
Add a config for attribute, if this config is set, the attribute can't be updated Add a parameter in update method to get all the attributes that are updated
Proposal
I wonder if this feature exist, or I just miss it. thank you
References
Hi @shiyuhang0 👋 Thank you for raising this. I'll answer your questions in two parts, since they appear to warrant separate answers.
Some attributes is needed when create, but they can not be updated. How can I throw errors when they are changed? now, I need to compare the plan and state and throw errors myself for the attributes can not be changed
A typical design for Terraform providers when encountering attributes that cannot be updated in-place is to have those attributes mark the resource for replacement during planning. This is generally preferred over returning errors during validation/planning as practitioners may be confused how to get out of their situation when the change is valid, if the resource was recreated (otherwise they would need to manually remove the existing resource from the state to use the updated configuration, or remove the resource from configuration then immediately re-add it).
When using terraform-plugin-framework, this can be accomplished by adding a built-in resource.RequiresReplace()
attribute plan modifier to the schema for the attribute. For example:
// other methods omitted for brevity
var _ provider.ResourceType = exampleResourceType{}
func (t exampleResourceType) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfsdk.Schema{
Attributes: map[string]tfsdk.Attribute{
"example_attribute": {
PlanModifiers: []tfsdk.AttributePlanModifier{
resource.RequiresReplace(),
},
Required: true,
Type: types.StringType,
},
},
}, nil
}
If for some reason your use case fits outside conventional provider implementations, taking a look at the implementation of resource.RequiresReplace()
and implementing your own attribute plan modifier that returns an error diagnostic instead of enabling the replacement boolean would likely be the way to go there.
Can I get the attributes that are updated? now, I also compare the plan and state to find out the changed attributes
This is currently an expected implementation detail, however it would be great to hear about your use case to see if there might be an enhancement that can be provided. One particular challenge is what the framework should return in this case.
- Returning attributes (and/or their paths) which have been updated would need to account for differences between configuration, proposed new state (plan), and the prior state. How would these distinctions be surfaced to provider developers?
- Returning attributes which have been updated would need to account for the type implementations of each attribute or the framework logic would return errors (similar to how calling
Get()
requires all Terraform attributes to be accounted for in thestruct
) -- if all attributes must be in thestruct
, how would non-updated attributes be surfaced? Does this require a whole new framework concept for attribute differences? - Returning attribute paths which have been updated would still require provider developers to implement switching logic for each attribute and its type, which I believe is effectively the same as today, minus the list of updated paths being immediately available.
If you can provide some additional thoughts for these questions or the possible usage of this type of functionality and how it ideally might look in provider code, that would be wonderful. Thanks.
Thank you for your reply!
For the first question, I don't want to replace
in my case. So, it seems I need to implement a new plan modifier. I will try it.
For the second question, I think I should introduce my case first. There are two attributes that can't be updated simultaneously via the API in my case. The HTTP request will return an error if I pass both parameters. In other words, only when an attribute changes can it be used to build into the HTTP request. So, I need to judge which one is updated.
I didn't consider the challenges you mentioned before, it looks more complicated than I thought.
For the first challenge. In my case, I'd like to get the attributes with different configurations and prior state, just like the execution plan showed after terraform apply
.
About the second challenge, I don't have good ideas too, maybe some new fields for UpdateRequest? For example, addedAttributes
for the attributes which are added, the same for deletedAttributes
and updatedAttributes
, and we can get the attribute name from them. Maybe a stupid idea, ignore it if it is not appropriate.
Could you show a pseudo-code example of what you might expect to write in your case?
Hi again, @shiyuhang0 👋 Since we haven't heard back in awhile about this, I'm going to close it for now so we can track active issues. If you would like to discuss it further, please feel free to re-open with a comment.
I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues. If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.