Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix invalid null blocks during refresh #32424

Merged
merged 3 commits into from Dec 21, 2022
Merged

Conversation

jbardin
Copy link
Member

@jbardin jbardin commented Dec 21, 2022

Legacy providers may return null values for nested blocks during refresh. Because the ReadResource call needs to accept any value to allow the provider to report external changes, we allowed all changes to the value as long as the underlying cty.Type was correct, allowing null block values to be inserted into the state.

While technically invalid, we needed to accept these null values for compatibility, and they were mostly seen as a nuisance, causing noise in external changes and plan output. These null block values however can be inserted into the effective configuration with the use of ignore_changes, which can cause problems where the configuration is assumed to be completely valid.

Rather than accept the null values, we can insert empty container values for these blocks when refreshing the instance, which will prevent any invalid values from entering state at all. Because these must still be accepted for compatibility, we can only log the difference as a warning. Currently the NormalizeObjectFromLegacySDK does not report which specific blocks it fixed, so we just log a generic message.

Legacy providers may return null values for nested blocks during
refresh. Because the ReadResource call needs to accept any value to
allow the provider to report external changes, we allowed all changes to
the value as long as the underlying cty.Type was correct, allowing
null block values to be inserted into the state.

While technically invalid, we needed to accept these null values for
compatibility, and they were mostly seen as a nuisance, causing noise in
external changes and plan output. These null block values however can be
inserted into the effective configuration with the use of
`ignore_changes`, which can cause problems where the configuration is
assumed to be completely valid.

Rather than accept the null values, we can insert empty container values
for these blocks when refreshing the instance, which will prevent any
invalid values from entering state at all. Because these must still be
accepted for compatibility, we can only log the difference as a warning.
Currently the NormalizeObjectFromLegacySDK does not report which
specific blocks it fixed, so we just log a generic message.
Copy link
Member

@apparentlymart apparentlymart left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems good to me but given that it's in the critical path I suggest we land it only in the main branch and not backport it, so it will get more opportunity to soak in prereleases.

(I see you weren't proposing to backport it anyway but just pre-registering an opinion on that in case the question comes up downstream somewhere.)

@bflad
Copy link
Member

bflad commented Dec 21, 2022

Is it worth discussing whether this sort of logic should also occur with terraform-plugin-framework, since currently the type system and provider response checking does not prevent list/set/single blocks from being stored as null?

@apparentlymart
Copy link
Member

From what I can see purely via thought experiment (i.e. I've not actually tested this) I don't think it's super important that the framework respect this rule when it is generating responses, although I imagine it also wouldn't hurt for the framework to respect this rule for consistency with the Terraform Core behavior.

So far this idea that nested block types can never appear as null or unknown has been a promise from Terraform Core to providers rather than the other way around. It was motivated by the fact that the legacy SDK (by which I specifically mean the helper/schema package we were still using at the time) had a few edge cases where it would behave poorly if given a null value or an unknown value as the direct value representing a block type. Specifically, it would do stuff like trying to type-assert to []interface{} without handling the situations where the value was either nil or the special string that represents unknown values. I'm not sure if those quirks are still present in what we now call SDKv2.

Aside from this gap where we ended up passing a value returned by a provider directly back to the same provider without modification, thereby effectively breaking the promise, I don't think Terraform Core actually worries too much about nested block types appearing as null. From Terraform Core's perspective all of this stuff is just cty.Value instances anyway; we preserved the blocks vs. attributes distinction at the configuration and protocol layers primarily because the legacy SDK was relying on it, not because it was greatly important to Terraform's overall behavior.

(That is, for example, why it was not a hugely big deal to add support for object types with block-like schema behaviors in protocol version 6; to Terraform Core they don't really look much different than nested block types, aside from the relaxation of the rule that they can never be null or unknown when sent to a provider.)

@jbardin jbardin merged commit 0e46d0a into main Dec 21, 2022
@jbardin jbardin deleted the jbardin/reify-null-blocks branch December 21, 2022 18:17
@github-actions
Copy link

Reminder for the merging maintainer: if this is a user-visible change, please update the changelog on the appropriate release branch.

@github-actions
Copy link

I'm going to lock this pull request because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active contributions.
If you have found a problem that seems related to this change, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jan 21, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants