Commit graph

148 commits

Author SHA1 Message Date
Alisdair McDiarmid
f3ec86b17b stackruntime: Treat unset and null equally
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.
2024-03-07 15:49:39 -05:00
Alisdair McDiarmid
0fe26468cd stackruntime: Apply defaults to root 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.
2024-03-04 16:20:17 -05:00
Daniel Schmidt
49ad27f1c9
Merge pull request #34737 from hashicorp/stacks-for-each
stacks: make component for_each more robust
2024-02-29 10:58:54 +01:00
Nick Fagerlund
c9c24706aa
Merge pull request #34741 from hashicorp/nf/feb24-provider-addrs-in-statuses
Stacks, Hooks: Include full provider addresses
2024-02-28 11:11:33 -08:00
Daniel Schmidt
2a0962328d
stacks: make error message more precise 2024-02-28 15:41:00 +01:00
Daniel Schmidt
8da61e2d20
stacks: reword for_each error message 2024-02-28 13:12:50 +01:00
Daniel Schmidt
217879e510
stacks: make component for_each more robust 2024-02-28 12:23:17 +01:00
Liam Cervante
cec4b7b74c
stacks: validate providers based on types instead of local names (#34735)
* stacks: validate providers based on types instead of local names

* fix tests
2024-02-28 08:24:53 +01:00
Nick Fagerlund
f58c71e77c Stacks: Update expectations in TestTerraformHook 2024-02-27 19:28:20 -08:00
Nick Fagerlund
7703a5aead Stacks: Add ProviderAddr field to ResourceInstanceStatusHookData
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.
2024-02-27 19:28:20 -08:00
Nick Fagerlund
94ea534e40 Refactor terraform.Hook to use a resource-identifying wrapper struct
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.
2024-02-27 19:28:20 -08:00
Liam Cervante
31a7fa88d5
stacks: validate provider configurations during static analysis (#34730) 2024-02-27 08:43:58 +01:00
Alisdair McDiarmid
1459825e53
Merge pull request #34725 from hashicorp/alisdair/configs-sourcebundle-parser
Add and use a source bundle aware configuration parser for stacks
2024-02-26 16:39:33 -05:00
Alisdair McDiarmid
2c22c213e9 stackeval: More robust absolute source addrs
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.
2024-02-26 14:48:29 -05:00
Alisdair McDiarmid
7a043fe54a stackeval: Another module source test case
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.
2024-02-26 14:16:03 -05:00
Alisdair McDiarmid
7d956bbc11 stackeval: Fix module loader source addr building
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.
2024-02-26 13:29:15 -05:00
Martin Atkins
a45d4467f1 stackeval: Don't fail when data resource is removed
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.
2024-02-26 08:14:16 -08:00
Liam Cervante
b2cc7dbadf
stacks: validate the types of input variables during validation (#34722) 2024-02-26 11:36:19 +01:00
Liam Cervante
68fd15dfdd
stacks: expand reference scope of static validations (#34721) 2024-02-26 11:26:22 +01:00
Liam Cervante
831630fabe
stacks: the plan function should stop on validation errors (#34720) 2024-02-26 10:42:14 +01:00
Alisdair McDiarmid
97a220fb82 stacks: Use source bundle aware config parser 2024-02-23 13:29:37 -05:00
Liam Cervante
b3abff5750
stacks: check providers blocks in components during validatation (#34707) 2024-02-21 11:07:51 +01:00
Liam Cervante
bced645a4d
stacks: call terraform.Validate on stack component configs (#34705) 2024-02-21 10:58:44 +01:00
Liam Cervante
2472f7c773
stacks: fix flaky tests (#34708) 2024-02-21 10:40:20 +01:00
Alisdair McDiarmid
48148eda5f
Merge pull request #34687 from hashicorp/alisdair/stackeval-hook-replace-action-counts
stackeval: Add support for replace actions to hook
2024-02-16 12:36:20 -05:00
Liam Cervante
64b311d53a
stacks: apply sensitive marks to outputs from components (#34684)
* stacks: apply sensitive marks to outputs from components

* gen headers

* ensure consistent test ordering
2024-02-16 10:46:50 +01:00
Liam Cervante
f0b61090a2
Move the testing MockProvider into a dedicated shared package (#34681)
* move the testing MockProvider into a dedicated shared package

* address comments

* fix new changes
2024-02-16 10:35:29 +01:00
Alisdair McDiarmid
06723d3d4b stackeval: Add support for replace actions to hook
The terraform.Hook implementation in stackeval is used to track the
operations performed during stack runtime operations, for later
reporting to the caller. This hook did not correctly support the replace
actions (create-then-destroy, destroy-then-create), resulting in a loss
of data between plan and apply. This exhibited as a plan with a replace
reporting 1 add and 1 remove operation, which when applied would report
only 1 add operation.

Previously, we stored the action performed for each apply operation on a
given resource instance in the PreApply hook, then allowed access to it
via the ResourceInstanceObjectAppliedAction method. Here we extend the
PostApply hook to look for a previous action performed on this instance,
and use that to reconstruct the planned replace action.

This method is called in the stackruntime package, where replace
operations are counted for both add and remove. No changes are needed at
the call site to fix the bug.
2024-02-15 16:37:56 -05:00
Martin Atkins
fde6277565 stackruntime: Pass ExperimentsAllowed into stackeval for apply
This was originally part of 7dad938fdb but
unfortunately seems to have got lost during some rebasing, or some other
similar sort of annoying reason.

This now allows the "experiments allowed" flag to propagate into the
stackeval package when we're running the apply phase, for consistency with
all of the other phases. Without this, it's possible to plan a
configuration that's participating in experiments, but then it fails in a
strange way during the apply step due to Terraform suddenly thinking it's
a stable release where experiments are disabled.
2024-02-15 10:25:20 -08:00
Liam Cervante
07f6621091
stacks: include resources in state when calculating required providers (#34645)
* stacks: include resources in state when calculating required providers

* also support apply time

* add copywrite headers
2024-02-15 10:45:47 +01:00
Martin Atkins
e6665c4f43 stackeval: Basic support for deferred-change propagation
This is the bare minimum functionality to ensure that we defer all actions
in any component that depends on a component that already had deferred
actions.

We will also eventually need to propagate out a signal to the caller for
whether the stack plan as a whole is complete or incomplete, but we'll
save that for later commits, since the stack orchestration in Terraform
Cloud will do the right thing regardless, aside from the cosmetic concern
that it won't yet know to show a message to the user saying that there
are deferred changes.
2024-02-12 12:13:08 -08:00
Martin Atkins
67d8a5137b rpcapi+stacks: Stacks runtime can see whether experiments are allowed
We allow experiments only in alpha builds, and so we propagate the flag
for whether that's allowed in from "package main". We previously had that
plumbed in only as far as the rpcapi startup.

This plumbs the flag all the way into package stackeval so that we can
in turn propagate it to Terraform's module config loader, which is
ultimately the one responsible for ensuring that language experiments can
be enabled only when the flag is set.

Therefore it will now be possible to opt in to language experiments in
modules that are used in stack components.
2024-02-12 12:13:08 -08:00
Liam Cervante
3475d22741
Fix nil pointer exception when planning stacks with undeclared variables (#34638)
* fix nil pointer exception when planning with undeclared variables

* another function does the same
2024-02-12 17:24:15 +01:00
Alisdair McDiarmid
55675b990a stackeval: Unmark provider config for plugin RPC
When validating or applying a provider configuration, we must unmark the
value before attempting to use plugin RPC, as we cannot serialize marks.
2024-02-09 15:38:25 -05:00
Martin Atkins
884e1fb2a4 terraform: Plans can be "complete" and "applyable"
These ideas are both already implied by some logic elsewhere in the system,
but until now we didn't have the decision logic centralized in a single
place that could therefore evolve over time without necessarily always
updating every caller together.

We'll now have the modules runtime produce its own boolean ruling about
each characteristic, which callers can rely on for the mechanical
decision-making of whether to offer the user an "approve" prompt, and
whether to remind the user after apply that it was an incomplete plan
that will probably therefore need at least one more plan/apply round to
converge.

The "Applyable" flag directly replaces the previous method Plan.CanApply,
with equivalent logic. Making this a field instead of a method means that
we can freeze it as part of a saved plan, rather than recalculating it
when we reload the plan, and we can export the field value in our export
formats like JSON while ensuring it'll always be consistent with what
Terraform is using internally.

Callers can (and should) still use other context in the plan to return
more tailored messages for specific situations they already know about
that might be useful to users, but with these flags as a baseline callers
can now just fall back to a generic presentation when encountering a
situation they don't yet understand, rather than making the wrong decision
and causing something strange to happen. That is: a lack of awareness of
a new rule will now cause just a generic message in the UI, rather than
incorrect behavior.

This commit mostly just deals with populating the flags, and then all of
the direct consequences of that on our various tests. Further changes to
actually make use of these flags elsewhere in the system will follow in
later commits, both in this repository and in other repositories.
2024-02-09 09:24:27 -08:00
Martin Atkins
0994e6fbf9 stacks: The terraform.workspace attr is not available in Stacks
The terraform.workspace attribute is a rare example of a CLI- and Cloud-
specific concern bleeding into the Terraform language, and it can only
really have meaning when used in the traditional Terraform workflow
because otherwise there's no workspace to return the name of.

In Stacks any variations between instances of a module must be created
through input variables. Within Terraform Cloud in particular it's also
possible to use stack-level input variables that are assigned different
values from different stack deployments, and thus an author can recreate
the effect of terraform.workspace using a stack-level input variable that
has a different value for each deployment.

This is one of the few cases where the Terraform module language differs
in stacks compared to traditional Terraform. Any module that makes use of
terraform.workspace will need to be generalized to use input variables
instead before it can be used within a stack component.

Prior to this change, references to terraform.workspace from a module used
in a stack component would just panic altogether, because the stacks
runtime doesn't provide the object that the workspace name would be taken
from. Now we'll return a user-oriented error instead.
2024-01-22 08:33:36 -08:00
Martin Atkins
7d2d4dec5e stackeval: When being destroyed, component instance result comes from plan
Because we treat dependency edges as reversed when a component instance
is being destroyed, the final result (an object representing output values)
for a component instance being destroyed must not depend on anything else
in the evaluation graph, or else we'd cause a promise self-reference as
the downstream component tries to configure itself based on our outputs.

As a special case then, for a component instance being destroyed we take
the planned output values directly from the plan, relying on the fact that
the plan phase sets them to the prior state output values in that case,
and therefore the result for such a component is available immediately
without blocking on any other expression evaluation during the apply phase.

This combines with several previous commits to create a first pass at
handling ordering correctly when planning and applying a full destroy.

This commit also incorporates some fixes and improvements to stackeval's
apply-time testing helpers, which had some quirks and bugs when first
added in a recent commit. One of those problems also revealed that the
raw state loader was not resilient to a buggy caller setting a state
entry to nil instead of removing it altogether, and that mistake seems
relatively easy to make (as I did here in the test helper) so we'll
tolerate it to make it possible to recover if such a bug does end up
occurring in real code too.
2024-01-15 15:20:48 -08:00
Martin Atkins
dcb176a557 stackeval: A Main for applying knows the plan it's applying 2024-01-15 15:20:48 -08:00
Martin Atkins
c06ad051a1 stackeval: Respect inter-component dependencies during apply
Before we start any apply-time actions for a particular component, we'll
block until other components' apply are complete.

In the normal case a component instance waits until its dependencies have
been applied. However, if component instances are being destroyed then
they instead wait for their _dependents_ to complete being applied, since
a component must outlive all other components that depend on it.
2024-01-15 15:20:48 -08:00
Martin Atkins
c345cde93c stackeval: Extended utilities for plan and apply testing
These helpers make it easier to write our tests because the plan and apply
phases both work in a callback-based fashion where they gradually emit
events, and that's not a very convenient API for test code to interact
with.

This exposes some more details about the planning results, and also adds
a new similar helper for the apply phase. We'll make use of both of these
in future commits.
2024-01-15 15:20:48 -08:00
Liam Cervante
9246b3a994
stacks: on module load convert relative paths to absolute (#34523) 2024-01-15 17:58:31 +01:00
Liam Cervante
7d143388f3
Add support for the cross resource type move operation in the proto schema (#34480)
* Update proto schema and provider interfaces with support for moved across resource type RPCs

* address comments

* remove unused functions

* remove support for flatmap format
2024-01-11 10:08:50 +01:00
Martin Atkins
3c14eeb945 stackeval: Make some provisioners available to stack components
This makes the built-in "remote-exec" and "file" provisioners available
for use in the modules that implement stack components. These are both
relatively easy and low-risk to include because they are builtins and
don't require anything from outside of Terraform itself.

For now this intentionally excludes local-exec because we'll want to think
about what constraints we want to put on it, if any, to help ensure we can
meet the goal of stack configurations being portable between different
execution environments without significant modification, and our current
stacks execution environment doesn't guarantee the availability of any
external software _at all_.

The motivation for adding this now is just to give some better feedback
when someone uses a module using one of these provisioners, since otherwise
they'll see just a confusing generic error message from the modules
runtime about the provisioners not being available. I expect we'll revisit
this later and consider expanding it to at least include local-exec, and
_maybe_ external provisioner plugins, although that's more questionable
because the provisioner plugin mechanism is incredibly legacy and doesn't
have any way to work outside of local Terraform CLI usage today.

There are no tests here yet because these provisioners are not mockable
and would depend on having an SSH or WinRM server to connect to. Later we
should ponder how to make this more testable, which might mean making
another part of the system responsible for actually providing the
provisioner factories and thus our tests here can use fakes. The goal here
is just to get this done in a relatively lightweight way for better
feedback during preview though, so we're not yet ready to make significant
time investments here.
2024-01-08 14:14:33 -08:00
Alisdair McDiarmid
1d3f863f2b stackruntime: Support sensitive component inputs
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.
2024-01-08 15:27:06 -05:00
Alisdair McDiarmid
e4b319401e stacksruntime: Add sensitive outputs tests 2024-01-08 15:27:06 -05:00
Martin Atkins
3961c18420 stackeval: Return an error if a module contains a provider config
When using stacks the provider configurations belong in the stack
configuration rather than inline in the individual modules.

Shared modules with inline provider configurations has been a deprecated
legacy practice for many years now, but traditional Terraform continued
to support it for backward-compatibility with older modules despite the
significant downsides of doing so. Stacks now finally removes that
capability, since it isn't straightforward to continue supporting it once
we've made the stacks runtime be responsible for instantiating and
configuring providers.
2024-01-08 12:12:41 -08:00
Martin Atkins
a51c034cc3 stackeval: Include component configurations in our static walks
This means both that the validate walk can now describe static problems in
the component's module tree, and that we'll catch such problems earlier
in the planning phase and thus avoid reporting them repeatedly in cases
where a component block uses for_each to declare multiple instances.

This includes a fix to a bug in StackConfig.Components, which was
incorrectly using the input variable declarations as the source for its
result, instead of the component declarations.
2024-01-08 12:12:41 -08:00
Martin Atkins
a3cd4a11ce stackeval: Use relative, slashy paths in module-related diagnostics
Until we've updated the module config loader to be sourcebundle-aware and
thus return proper source addresses, this will at least make the paths
we show in diagnostics a little less verbose, and more consistent across
platforms.
2024-01-08 12:12:41 -08:00
Martin Atkins
a4d61733f6 stackplan: Include extra info in raw component instance plan
We'll now track the planned action, the component addresses we depend on,
and the planned output values.
2024-01-08 10:52:01 -08:00
Martin Atkins
25a514f846 stackeval: Populate planned component instance more thoroughly
We'll now track a more realistic Action, the components that the component
instance depends on, and the planned output values.
2024-01-08 10:52:01 -08:00