This implementation is very barebones, but builds the skelleton for
all upcoming features in actions. It includes the graph implementation
for planning actions including the expansion of actions and dealing
with multiple action triggers.
We plan all actions as part of their triggering resource for now.
All action_triggers depend on the triggering resources plan to
determine if an action should run or not, therefore we can plan
the actions as part of the triggering resource.
This implementation ignores conditions, deferrals, provider arguments
and it does not add the actions to the planfile; mostly to enable more
people to work on these issues in parallel.
The internal API here was a little unclear, so this is just some
retroactive additional documentation resulting from me having "relearned"
how this API works after some time away from it, in the hope that future
maintainers will not need to repeat that exercise.
This is a similar idea to Expander.ExpandModule but for situations where
we already know exactly which containing module we're evaluating inside,
and thus we can just pluck out the leaf instance keys of that specific
dynamic call, rather than the full recursive expansion of every containing
module.
Expander.ExpandModule is useful when implementing DynamicExpand for a
graph node because main graph nodes always represent static configuration
objects, but this new Expander.ExpandAbsModuleCall is more appropriate
for use during expression evaluation of references to a module call
because in that case we'll know which specific module instance address
we're using as the evaluation scope.
A future commit will actually use this new method from the expression
evaluator in the modules runtime.
Recently we've introduced the idea of the expansion of a particular module
or resource not yet being known, which has inadvertently introduced some
ambiguity about what "unknown" means in this package: "unknown" previously
represented "not registered yet", which is different than having
explicitly registered that we don't know.
To remove that ambiguity, we'll now use the term "unregistered" to talk
about the "not registered yet" situation, and reserve "unknown" for when
we know that we definitely don't know.
This is only an internal naming change within the package and doesn't
affect any exported API.
These new methods both take into account the possibility of there being
unknown keys, which will be useful for the expression evaluator to decide
whether it can return a specific type or not.
Now that Expander can support unknown expansions for modules and resource
instances, we'll need some placeholders to use when evaluating the
configurations of those objects to predict as much as possible what the
final configurations of all of their instances will look like.
This is a similar problem to checking whether a not-yet-expanded object
has valid configuration during the "validate" phase: we're essentially
asking what configuration all instances of the object will have in common,
and leaving unknown anything that might vary between instances.
Nothing is using these yet, but uses will follow in later commits.
This is the resource instance equivalent of UnknownModuleInstances added
in an earlier commit, returning a result that represents a set of possible
resource instance addresses that _might_ be declared by the
currently-unknown count or for_each argument.
This new method effectively returns a set of all of the instances of a
particular module whose addresses can't be fully determined yet, but does
so in the form of a set of patterns that match all of those as-yet-unknown
instance addresses.
So far this isn't used anywhere but in a future commit Terraform Core can
use this to generate placeholder unknown values when walking inside
unexpanded modules once we make it legal to have an unknown value for
the repetition argument of a module call.
In preparation for supporting partial planning when count or for_each are
not known enough to finalize instance keys, this allows the core graph
walk to register when it encounters an object whose repetition argument
isn't yet "known enough" to actually expand, which then allows downstreams
to still expand the subset of instances whose addresses are fully known
but (for now) quietly ignores any subtrees under objects that cannot be
expanded yet.
In subsequent commits we'll add additional API for finding the partial
addresses of objects that _cannot_ fully expand yet, so that the graph
walk can still keep track of those and report them to the user.
instances.Set is only used after all instances have been processes, so
it should therefor only handle known instances and not panic when given
an address that traverses an unexpanded module.
Previously we were treating it as a programming error to ask for the
instances of a resource inside an instance of a module that is declared
but whose declaration doesn't include the given instance key.
However, that's actually a valid situation which can arise if, for
example, the user has changed the repetition/expansion mode for an
existing module call and so now all of the resource instances addresses it
previously contained are "orphaned".
To represent that, we'll instead say that an invalid instance key of a
declared module behaves as if it contains no resource instances at all,
regardless of the configurations of any resources nested inside. This
then gives the result needed to successfully detect all of the former
resource instances as "orphaned" and plan to destroy them.
However, this then introduces a new case for
NodePlannableResourceInstanceOrphan.deleteActionReason to deal with: the
resource configuration still exists (because configuration isn't aware of
individual module/resource instances) but the module instance does not.
This actually allows us to resolve, at least partially, a previous missing
piece of explaining to the user why the resource instances are planned
for deletion in that case, finally allowing us to be explicit to the user
that it's because of the module instance being removed, which
internally we call plans.ResourceInstanceDeleteBecauseNoModule.
Co-authored-by: Alisdair McDiarmid <alisdair@users.noreply.github.com>
This is a first pass at implementing refactoring.ValidateMoves, covering
the main validation rules.
This is not yet complete. A couple situations not yet covered are
represented by commented test cases in TestValidateMoves, although that
isn't necessarily comprehensive. We'll do a further pass of filling this
out with any other subtleties before we ship this feature.
In order to precisely implement the validation rules for "moved"
statements we need to be able to test whether particular instances were
declared in the configuration.
The instance expander is the source of record for which instances we
decided while creating a plan, but it's API is far more involved than what
our validation rules need, so this new AllInstances method returns a
wrapper object with a more straightforward API that provides read-only
access to just the question of whether particular instances got registered
in the expander already.
This API covers all three of the kinds of objects that move statements can
refer to. It includes module calls and resources, even though they aren't
_themselves_ "instances" in the sense we usually mean, because the module
instance addresses they are contained within _are_ instances and so we
need to take their dynamic instance keys into account when answering these
queries.
This is part of a general effort to move all of Terraform's non-library
package surface under internal in order to reinforce that these are for
internal use within Terraform only.
If you were previously importing packages under this prefix into an
external codebase, you could pin to an earlier release tag as an interim
solution until you've make a plan to achieve the same functionality some
other way.
This is part of a general effort to move all of Terraform's non-library
package surface under internal in order to reinforce that these are for
internal use within Terraform only.
If you were previously importing packages under this prefix into an
external codebase, you could pin to an earlier release tag as an interim
solution until you've make a plan to achieve the same functionality some
other way.