When handling root input variable values, we now consider unset and null
values to be equivalent to each other. This is consistent with how we
handle variables in embedded stacks, and very similar to how we handle
variable in the modules runtime with `nullable = false`.
One difference from the modules runtime case is that we do not prevent
a null default value for stack variables.
When evaluating a stack's root input variables, supplied by the caller,
we must apply any default values specified in the variable
configuration for variables with no specified value. This commit adds
this default fallback case, using NilVal as a marker indicating the lack
of a specified value.
If no default value exists for a variable, it is therefore required to
be supplied by the caller. This commit also reports a diagnostic error
in this case.
Components can emit sensitive values as outputs, which can be consumed
as inputs to other components. This commit ensures that such values are
correctly processed in order to pass their sensitivity to the modules
runtime.
We've now upgraded the go-slug dependency to a newer version that fixed
the bug that this FIXME comment was referring to, so we can now write the
source address correctly and remove the note.
Instead of the temporary hack of hard-coding the built-in "terraform"
provider, it's now possible to declare configurations for arbitrary
providers and assign them to the provider configuration slots of the root
module of each component.
Each declared provider configuration is now started up and configured
during planning. We don't actually do anything with them yet other than
shut them down again once the plan is complete, but we'll improve on that
in subsequent commits.
This means it's valid to write references like "component.foo" in
expressions in a stack configuration, where the result is built from the
planned output values of the root module of each component instance.
For embedded stacks we intentionally designed the language to require
explicit types on all output values so that we'd still be able to do type
checking even when we can't calculate the output values yet. Unfortunately
we can't do the same trick for components because the main Terraform
module language treats output values as dynamically-typed and so an
output value we can't evaluate yet could have literally any type.
Therefore we concede and just return cty.DynamicVal in most failure cases
here; perhaps a future edition of the main Terraform language can improve
this by requiring explicitly-typed output values there too.
This is the absolute bare-minimum integration with the main Terraform
language runtime to plan changes for a component. It's intentionally not
yet very robust and limited only to the built-in Terraform provider
because we're just trying to get the bones in place for seeing stack
planning working, rather than trying to build something complete enough
to ship.
This currently only deals with the resource instance changes that get
planned and doesn't expose the root module's output values for use
elsewhere in the stack configuration. Output value handling will follow
in subsequent commits.
This is the public entry point for the overall validation of an entire
stack configuration. So far it supports validation only of input variables,
embedded stack calls, and output values. We'll grow this to support other
language constructs in later commits.
This is a relatively large commit due to introducing various supporting
infrastructure to help make evaluation possible at all. Subsequent commits
will hopefully be more focused due to being able to depend on the
foundations introduced here.
This stubs out the basic structure of stackeval's equivalent of a graph
walk, which is really just a recursive tree walk starting async tasks that
might depend on each other via the abstractions in package "promising".
This initial work is sufficient to validate the inputs to an embedded
stack call when referring to input variables in the calling stack, showing
that the expression evaluation model seems to be working and the use of
promises to deal with dependency ordering seems viable.