-
Notifications
You must be signed in to change notification settings - Fork 9.6k
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
[WIP] Ephemeral Values prototype #35077
Commits on Nov 29, 2023
-
providers: Allow providers to "defer" certain requests
For any request that can occur during the planning phase there is a chance that either a resource configuration or its associated provider configuration will contain unknown values that are placeholders for results of operations that haven't yet completed. Ideally a provider would be able to just do its best to predict the outcome in spite of the partial information, but in practice that isn't always possible. In those more complex situations it's better to let the provider explicitly decline to complete the operation and have Terraform Core defer it for a future run when there's hopefully more information available due to having applied other changes upstream. This commit does not yet introduce the idea of "deferred changes" into Terraform Core, so as a temporary step Terraform Core will just return an error if a provider tries to defer anything. In future commits we'll teach Terraform Core how to handle this more gracefully by saving partial results into the plan as "deferred changes" and then continuing on to downstream resources to try to gather as much information as possible to help the user understand the likely effects of those deferred actions.
Configuration menu - View commit details
-
Copy full SHA for 3ec4e9b - Browse repository at this point
Copy the full SHA 3ec4e9bView commit details -
addrs: Deferrable address types
This represents the two address types that could potentially have deferred actions associated with them during a Terraform plan operation, because deferring can happen either before or after instance expansion.
Configuration menu - View commit details
-
Copy full SHA for b5296a4 - Browse repository at this point
Copy the full SHA b5296a4View commit details -
Configuration menu - View commit details
-
Copy full SHA for 0c595bf - Browse repository at this point
Copy the full SHA 0c595bfView commit details -
core: Register unknown count and for_each with instance expander
Previously we just immediately bailed out with an error if either count or for_each were not sufficiently known to determine their full set of instance keys. The Expander abstraction can now talk about module calls and resources having unknown expansion, so Terraform Core should tolerate that situation and just let the expander know that the expansion is unknown, and then we'll deal with that situation downstream. For now "downstream" actually means directly after these functions return, because the rest of Terraform Core isn't yet ready to deal with objects that don't know their full expansions. We'll just return errors similar to (but slightly lower quality than) the ones we used to return during evaluation, as a temporary placeholder to keep things working until we get downstream more ready to deal with this. While working on this I also noticed that we were redundantly re-evaluating the for_each expressions for each resource instance just to prepare the repetition data, which is unnecessary because the Expander abstraction already keeps track of that to ensure that all of the graph nodes have a consistent view of the expansions. We'll now just ask the expander directly what our RepetitionData should be, since that's part of the expander's responsibility.
Configuration menu - View commit details
-
Copy full SHA for c7d76f0 - Browse repository at this point
Copy the full SHA c7d76f0View commit details -
addrs: Getting the parent of a PartialExpandedModule
Traversing upward from a PartialExpandedModule is trickier than traversing down because we need to deal with what happens if the traversal crosses over the boundary from partial-expanded into fully-expanded. To deal with that we end up having two different methods to handle the two situations, and a third method to indicate which one to call. Thankfully the need to ask for the parent of a partial-expanded module is relatively rare -- mainly just for input variables whose definitions need to eval in the parent module's scope -- so this awkward API shouldn't be needed in two many places.
Configuration menu - View commit details
-
Copy full SHA for f7f210e - Browse repository at this point
Copy the full SHA f7f210eView commit details -
terraform: Initial implementation of partial-expanded input variables
This is mainly just a proof-of-concept of what it might look like to generate graph nodes representing placeholders for objects in not-fully-expanded modules. These new codepaths are not really accessible yet because it's still invalid to have a module whose expansion is unknown; we'll continue down this path further in later commits once there's actually somewhere to save the partially-evaluated placeholder values.
Configuration menu - View commit details
-
Copy full SHA for 40d525f - Browse repository at this point
Copy the full SHA 40d525fView commit details -
core: Graph walk is aware of partial-expanded module paths
Our evaluation strategy for module-namespaced objects unfortunately depends quite strongly on having the right EvalContext in scope for each graph node, referring to the appropriate namespace in which to evaluate expressions. Although I was pretty reluctant to integrate the idea of partial-expanded module paths at quite this low a level, it does seem like the most pragmatic answer since it works with rather than against the existing evaluation strategies. As of this commit this isn't really doing anything because it isn't possible to reach any graph node that has a partial-expanded path and the EvalContext itself doesn't actually properly support evaluation in a partial-expanded path anyway; we'll fix up the rest of this in later commits before making these codepaths reachable.
Configuration menu - View commit details
-
Copy full SHA for b000ef5 - Browse repository at this point
Copy the full SHA b000ef5View commit details -
core: use namedvals.State to track input variable evaluation
This replaces the direct manipulation of a map shared between three different components, encapsulating that manipulation now inside a single wrapping API that itself ensures safe concurrent access. In future commits we'll do the same for local values and output values, but for now those part of namedvals.State remain unused.
Configuration menu - View commit details
-
Copy full SHA for cd4a221 - Browse repository at this point
Copy the full SHA cd4a221View commit details -
core: Remove variable-specific methods from EvalContext
Now that we have the separate namedvals.State type to encapsulate all of the named-value tracking we can simplify the EvalContext API to just return that object directly. This removes the slightly odd evolved API for setting and retrieving input variable values, instead now just calling directly into the relevant namedvals.State methods. It also slightly simplifies some of our test code because there's no longer any need to mock accesses to what is just a temporary in-memory data store anyway. Finally, this now gives nodePartialExpandedModuleVariable somewhere to save its placeholder values, though there's not yet anything to read them.
Configuration menu - View commit details
-
Copy full SHA for 52bafe3 - Browse repository at this point
Copy the full SHA 52bafe3View commit details -
core: Start of integrating "partial eval" mode into the evaluator
This is a new mode for the evaluator where instead of returning information about exact objects it'll return placeholder values that represent potentially many different hypothetical objects all declared from the same static configuration object, in situations where we don't yet have enough information to expand all of the modules and their contents. So far only the GetInputVariable function actually knows how to deal with this, so this is far from sufficient but is a reasonable starting point just to establish that it's possible to get Terraform into this evaluation mode when working with graph nodes that represent such placeholder objects.
Configuration menu - View commit details
-
Copy full SHA for 60fdd21 - Browse repository at this point
Copy the full SHA 60fdd21View commit details -
states: Local values no longer live in state
Back when we added local values (a long time ago now!) we put their results in state mainly just because it was the only suitable shared data structure to keep them in. They are a bit ideosyncratic there because we intentionally discard them when serializing state to a snapshot, and that's just fine because they never need to be retained between runs anyway. We now have namedvals.State for all of our named value result storage needs, so we can remove the local-value-related fields of states.Module and use the relevant map inside the local value state instead.
Configuration menu - View commit details
-
Copy full SHA for 36307c2 - Browse repository at this point
Copy the full SHA 36307c2View commit details -
core: Evaluate placeholders for local values in unexpanded modules
For any local value declared beneath a module call whose expansion isn't known yet, we'll calculate a single value to serve as a placeholder for all possible valid instances of that local value, using unknown values in any situation where a value might differ between instances.
Configuration menu - View commit details
-
Copy full SHA for 73a82df - Browse repository at this point
Copy the full SHA 73a82dfView commit details -
states: Only track root module output values
For a very long time we've had an annoying discrepancy between the in-memory state model and our state snapshot format where the in-memory format stores output values for all modules whereas the snapshot format only tracks the root module output values because those are all we actually need to preserve between runs. That design wart was a result of us using the state both as an internal and an external artifact, due to having nowhere else to store the transient values of non-root module output values while Terraform Core does its work. We now have namedvals.State to internally track all of the throwaway results from named values that don't need to persist between runs, so now we'll use that for our internal work instead and reserve the states.State model only for the data that we will preserve between runs in state snapshots. The namedvals internal model isn't really designed to support enumerating all of the output values for a particular module call, but our expression evaluator currently depends on being able to do that and so we have a temporary inefficient implementation of that which just scans the entire table of values as a stopgap just to avoid this commit growing even larger than it already is. In a future commit we'll rework the evaluator to support the PartialEval mode and at the same time move the responsiblity for enumerating all of the output values into the evaluator itself, since it should be able to determine what it's expecting by analyzing the configuration rather than just by trusting that earlier evaluation has completed correctly. Because our legacy state string serialization previously included output values for all modules, some of our context tests were accidentally depending on the implementation detail of how those got stored internally. Those tests are updated here to test only the data that is a real part of Terraform Core's result, by ensuring that the relevant data appears somewhere either in a root output value or in a resource attribute. As of this commit, what remains of the states.State model can now be entirely serialized by the state snapshot format, with no more situations where we just silently drop some data that Terraform Core uses as an implementation detail.
Configuration menu - View commit details
-
Copy full SHA for 33e909e - Browse repository at this point
Copy the full SHA 33e909eView commit details -
core: The expression evaluator has access to the instances.Expander
This will allow it to determine which instances _should_ be present rather than just trusting which instances _are_ present, which will make it harder to accidentally hide graph ordering bugs behind fallback behavior and, more importantly, will allow the evaluator to recognize the difference between there being no instances at all or the instance keys not yet being known.
Configuration menu - View commit details
-
Copy full SHA for c1593dc - Browse repository at this point
Copy the full SHA c1593dcView commit details -
Configuration menu - View commit details
-
Copy full SHA for 0d994a5 - Browse repository at this point
Copy the full SHA 0d994a5View commit details -
core: Expression evaluator can handle partial-eval in GetModule
This is a totally different approach to GetModule which uses the configuration and previously-registered expansion to determine what ought to exist in our named values state, rather than treating the values in the named values state as the source of truth. As a result we get an overall simpler implementation which is able to panic if other components aren't behaving correctly, and we can return placeholder results in partial evaluation mode, at least as long as we're working with a single-instance module. There are some further opportunities for simplification and improving the detail of the unknown results if we make broader changes in future, but for the moment this is just enough to mimic the previous behavior using a new strategy.
Configuration menu - View commit details
-
Copy full SHA for 6f577d2 - Browse repository at this point
Copy the full SHA 6f577d2View commit details -
core: Beginnings of placeholders for resources with unknown expansion
This doesn't actually do anything useful yet, but at least stubs out how evaluation for these might work in later commits.
Configuration menu - View commit details
-
Copy full SHA for 14f54c5 - Browse repository at this point
Copy the full SHA 14f54c5View commit details