Handling terraform import and a sometimes required attribute

For context, I’ve defined a required attribute (csr) within a resource as it’s a mandatory parameter for the upstream API within Create(). It’s not however returned by the API. My Update() method checks for equality between the planned and state value for this attribute in order to dynamically adjust the upstream API call. Technically the csr attribute is only required during Update() if the user wants to follow a specific flow of the update logic.

I’ve just implemented import functionality for this resource which exposed an issue with said attribute. As expected, the attribute is set to null, if the csr is already defined in configuration this then triggers an update, which will ultimately result in an error from the upstream API due to a duplicate csr being provided.

To combat this I’ve adjusted the attribute to be optional , which upon further reflection is conceptually quite fair. I wouldn’t expect a user importing the resource to necessarily have the original csr… The only aspect that falls short in is the fact that if the attribute is now omitted during resource creation the user will receive an API error, granted this correctly highlights the missing csr anyway but it would be nice if this occurred during validation.

I’ve had a quick look at write-only attributes and this seems to almost fulfil my needs. I initially disregarded this approach as I’d no longer be able to check for equality between the planned and state value in my Update() function which is a key requirement. I did just notice:

  • Use the resource’s private state to store secure hashes of write-only argument values, the provider will then use the hash to determine if a write-only argument value has changed in later Terraform runs.

That sounds like I’d be able to replicate my current functionality while using a write-only attribute. Planning to test out this theory but I wanted a sense check on the above, is this an idiomatic path forwards or am I missing something else? Thanks.

Yes, write-only attributes serve a couple purposes, but both reasons are not required to use them.

  • They allow a resource to use an ephemeral value, and not store that value in Terraform state.
  • They provide another way for resources to handle an attribute which is effectively write-only like your csr attribute.

Capturing the write-only value in the private state data for comparison will allow you to detect configuration changes, though given your description of the remote API, there is still no way to detect a change to the csr attribute if the resource were imported, but that’s not something Terraform can solve if the data is not available at all.

Thank you.

there is still no way to detect a change to the csr attribute if the resource were imported, but that’s not something Terraform can solve if the data is not available at all.

Correct, I don’t think this is something I’ll plan to solve currently to be honest.

Capturing the write-only value in the private state data for comparison will allow you to detect configuration changes

Are there any examples of this? I’ve had a quick play around with something like

Create() {
...
diags := resp.Private.SetKey(ctx, "key", []byte(myStringAtrribute))
...
}

PlanModifyString() {
...
value, diags := req.Private.GetKey(ctx, "key")
if string(value) != req.ConfigValue.ValueString() {
		resp.PlanValue = req.ConfigValue
	}
}

Which produces a Error: Provider produced invalid plan as we’re setting a value for the write-only attribute, which does make sense.. How else would we propagate the new configuration attribute to Update()?

Yes, you can’t set the write-only attribute, you just need to accept that you can access it from the config during apply. This means that you can’t plan a change to the write-only attribute alone, because a write-only attribute can’t really “change”. What you can do is mark computed attributes as unknown, telling Terraform that something needs to be done during apply. If you need to replace the resource because of the change to the write-only attribute, you can tell Terraform that the write-only attribute is the cause of replacement.

So I think because this requires some sort of coordination between attribute values you need to do the work in a resource plan modifier. I’d have to check how the rest of these concepts translate into the framework, but maybe this is enough to point you in the right direction.