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.
Due to some specific circumstances around how this experiment reached
stabilization we made a planned-temporary exception to make it valid to
specify even in non-alpha builds of Terraform, just to be able to return
a more precise error message.
The comment added at the time suggested that we remove this "a release or
two after v1.3", and v1.8 is the actively-developed release at the time
I'm writing this so we've kept this around far longer than we originally
felt we needed to. It's time for it to go.
This particular experiment will now get the same treatment as all others
when used in a non-alpha release: Terraform will return the general error
about experiments only being available in alpha releases.
We may revise this further during the Terraform v1.8 prerelease period, if
feedback suggests that more information is needed or that this information
is not clear enough. The main goal here is just to get out of the confusing
situation where the v1.8 branch contains a v1.7 upgrade guide, so that
we can link to the upgrade guide from the changelog.
The full upgrade guide page gives us room for more details, allowing the
changelog to serve just as a concise list of changes.
This updates the `ReportResourceInstanceStatus` and
`ReportResourceInstancePlanned` callbacks to extract the provider address they
received in their arguments and include it in the RPC messages they emit.
The corresponding RPC message formats were recently updated to include a field
for provider address.
The planned callback already could have accessed the provider address prior to
this PR, but the status callback needed the recent refactor of the
`terraform.Hook` API.
This updates the stackruntime `hooks.ResourceInstanceStatusHookData` struct to
include the provider address, and updates everything that instantiates that
struct to pass along the valid provider address it received from its own caller.
In other words, this commit is a bridge between the terraform.Hook interface
methods (which already have access to the provider address) and the stacks hook
callbacks that result in RPC messages being sent to the agent.
The terraform.Hook interface lets other areas of code perform streaming
reactions to various events, generally in the service of some UI somewhere.
Nearly all of the methods on this interface take an `addrs.AbsResourceInstance`
as their first argument, to identify the resource that's being operated on.
However, that addrs struct doesn't necessarily contain everything you might want
in order to uniquely and usefully identify a resource. It has the module
instance and resource instance addresses, but it lacks the provider source
address, which can affect how the consuming UI should display the resource's
events. (For example, Terraform Cloud wants reliable info about who maintains a
given provider, what cloud provider it operates on, and where to find its
documentation.)
Instead of polluting `addrs.AbsResourceInstance` with extra information that
isn't relevant to other call sites, let's change the first argument of each Hook
method to be a wrapper struct defined in the package that owns the Hook
interface, and add the provider address to that wrapper as a sibling of the
resource address. This causes a big noisy commit today, but should streamline
future updates to the UI-facing "identity" of a resource; existing callers can
ignore any new fields they're uninterested in, or exploit new info as needed.
Other than making new information available for future edits to Hook
implementing types, this commit should have no effect on existing behavior.
Using the new possibility of provider-contributed functions, this
introduces three new functions which live in the
terraform.io/builtin/terraform provider, rather than being language
builtins, due to their Terraform-domain-specific nature.
The three new functions are:
- tfvarsencode: takes a mapping value and tries to transform it into
Terraform CLI's "tfvars" syntax, which is a small subset of HCL that
only supports key/value pairs with constant values.
- tfvarsdecode: takes a string containing content that could potentially
appear in a "tfvars" file and returns an object representing the
raw variable values defined inside.
- exprencode: takes an arbitrary Terraform value and produces a string
that would yield a similar value if parsed as a Terraform expression.
All three of these are very specialized, of use only in unusual situations
where someone is "gluing together" different Terraform configurations etc
when the usual strategies such as data sources are not suitable. There's
more information on the motivations for (and limitations of) each function
in the included documentation.
Changes between empty strings and `null` were hidden in the CLI output,
because the SDK could not reliably detect the difference and may return
either value depending on the situation.
This legacy behavior can be confusing for authors of new provider which
can correctly handle `null`, and it would be preferable to be able to
render those changes in the CLI.
While we don't have enough information to detect when the legacy
behavior is required, we can detect a number of cases where it's
certain that we are not dealing with a legacy schema and should output
the full diff.
Instead of relying on the module call's source being unique, we now use
the entire path as the key for looking up the parent's absolute source
address.
If multiple submodules of a given component share the same relative
source, they should result in distint source addresses in the
diagnostics. This commit introduces an example with the following
structure:
- component.remote_invalid_grandchildren
- module.first_child
- module.child (source = "./child")
- module.second_child
- module.child (source = "./child")
Both of these use the same invalid module as the rest of the examples in
this test, so we should (and do) see equivalent diagnostics differing
only in filename.
The source bundle aware module loader requires "absolute" source
addresses, which are fully qualified rather than relative. We generate
these during the module loading process.
The previous implementation assumed that any local module source address
should be parented by the root module source, but this is incorrect when
a descendant module targets a remote or registry source. This commit
addresses this by tracking each module request's generated absolute
source address, and using it as the base for any descendant local module
requests.
Due to an oversight in our handling of resource instance objects that are
neither in configuration nor plan -- which is true for data resources that
have since been removed from the configuration -- we were generating plan
change objects that were lacking a provider configuration address, which
made them syntactically invalid and thus not reloadable using the
raw plan parser.
This is a bit of a strange situation since we don't technically _need_ a
provider configuration address for these; all we're going to do is just
unceremoniously delete them from the state during apply anyway. However,
we always have the provider configuration address available anyway, so
adding this in here is overall simpler than changing the parser, the
models it populates, and all of the downstream users of those models to
treat this field as optional.
This commit is more test case than it is fix, since the fix was relatively
straightforward once I had a test case to reproduce the problem it's
fixing.