2023-09-21 04:53:02 -05:00
# OpenTofu Core Architecture Summary
2019-03-21 19:59:06 -05:00
2023-09-21 04:53:02 -05:00
This document is a summary of the main components of OpenTofu Core and how
2019-03-21 19:59:06 -05:00
data and requests flow between these components. It's intended as a primer
to help navigate the codebase to dig into more details.
2023-09-21 04:53:02 -05:00
We assume some familiarity with user-facing OpenTofu concepts like
configuration, state, CLI workflow, etc. The OpenTofu website has
2019-03-21 19:59:06 -05:00
documentation on these ideas.
2023-09-21 04:53:02 -05:00
## OpenTofu Request Flow
2019-03-21 19:59:06 -05:00
The following diagram shows an approximation of how a user command is
2023-09-21 04:53:02 -05:00
executed in OpenTofu:
2019-03-21 19:59:06 -05:00
2023-09-21 04:53:02 -05:00
![OpenTofu Architecture Diagram, described in text below ](./images/architecture-overview.png )
2019-03-21 19:59:06 -05:00
Each of the different subsystems (solid boxes) in this diagram is described
in more detail in a corresponding section below.
## CLI (`command` package)
2023-09-21 04:53:02 -05:00
Each time a user runs the `tofu` program, aside from some initial
2019-03-21 19:59:06 -05:00
bootstrapping in the root package (not shown in the diagram) execution
transfers immediately into one of the "command" implementations in
2023-09-20 06:35:35 -05:00
[the `command` package ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/command ).
2019-03-21 19:59:06 -05:00
The mapping between the user-facing command names and
their corresponding `command` package types can be found in the `commands.go`
2024-04-01 05:47:22 -05:00
file under the `cmd/tofu` directory (package `main` ).
2019-03-21 19:59:06 -05:00
The full flow illustrated above does not actually apply to _all_ commands,
2023-09-21 04:53:02 -05:00
but it applies to the main OpenTofu workflow commands `tofu plan` and
`tofu apply` , along with a few others.
2019-03-21 19:59:06 -05:00
2020-07-22 11:24:32 -05:00
For these commands, the role of the command implementation is to read and parse
2019-03-21 19:59:06 -05:00
any command line arguments, command line options, and environment variables
that are needed for the given command and use them to produce a
2023-09-20 06:35:35 -05:00
[`backend.Operation` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/backend#Operation )
2019-03-21 19:59:06 -05:00
object that describes an action to be taken.
An _operation_ consists of:
* The action to be taken (e.g. "plan", "apply").
2023-09-21 04:53:02 -05:00
* The name of the [workspace ](https://opentofu.org/docs/language/state/workspaces )
2019-03-21 19:59:06 -05:00
where the action will be taken.
* Root module input variables to use for the action.
* For the "plan" operation, a path to the directory containing the configuration's root module.
* For the "apply" operation, the plan to apply.
* Various other less-common options/settings such as `-target` addresses, the
"force" flag, etc.
The operation is then passed to the currently-selected
2023-09-21 04:53:02 -05:00
[backend ](https://opentofu.org/docs/language/settings/backends/configuration ). Each backend name
2019-03-21 19:59:06 -05:00
corresponds to an implementation of
2023-09-20 06:35:35 -05:00
[`backend.Backend` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/backend#Backend ), using a
2019-03-21 19:59:06 -05:00
mapping table in
2023-09-20 06:35:35 -05:00
[the `backend/init` package ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/backend/init ).
2019-03-21 19:59:06 -05:00
Backends that are able to execute operations additionally implement
2023-09-20 06:35:35 -05:00
[`backend.Enhanced` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/backend#Enhanced );
2019-03-21 19:59:06 -05:00
the command-handling code calls `Operation` with the operation it has
constructed, and then the backend is responsible for executing that action.
2021-12-07 15:07:22 -06:00
Backends that execute operations, however, do so as an architectural implementation detail and not a
2023-09-21 04:53:02 -05:00
general feature of backends. That is, the term 'backend' as a OpenTofu feature is used to refer to
2023-10-12 06:11:01 -05:00
a plugin that determines where OpenTofu stores its state snapshots - only the default `local` , `remote` and `cloud` backends perform operations.
2021-12-07 15:07:22 -06:00
Thus, most backends do _not_ implement this interface, and so the `command` package wraps these
backends in an instance of
2023-09-20 06:35:35 -05:00
[`local.Local` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/backend/local#Local ),
2023-09-21 04:53:02 -05:00
causing the operation to be executed locally within the `tofu` process itself.
2019-03-21 19:59:06 -05:00
## Backends
2023-09-21 04:53:02 -05:00
A _backend_ determines where OpenTofu should store its state snapshots.
2019-03-21 19:59:06 -05:00
2021-12-07 15:07:22 -06:00
As described above, the `local` backend also executes operations on behalf of most other
backends. It uses a _state manager_
2019-03-21 19:59:06 -05:00
(either
2023-09-20 06:35:35 -05:00
[`statemgr.Filesystem` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/states/statemgr#Filesystem ) if the
2019-03-21 19:59:06 -05:00
local backend is being used directly, or an implementation provided by whatever
backend is being wrapped) to retrieve the current state for the workspace
specified in the operation, then uses the _config loader_ to load and do
initial processing/validation of the configuration specified in the
operation. It then uses these, along with the other settings given in the
operation, to construct a
2023-10-12 06:11:01 -05:00
[`tofu.Context` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/tofu#Context ),
2023-09-21 04:53:02 -05:00
which is the main object that actually performs OpenTofu operations.
2019-03-21 19:59:06 -05:00
The `local` backend finally calls an appropriate method on that context to
begin execution of the relevant command, such as
2023-09-21 04:53:02 -05:00
[`Plan` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/tofu#Context.Plan )
2019-03-21 19:59:06 -05:00
or
2023-09-21 04:53:02 -05:00
[`Apply` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/tofu#Context.Apply ), which in turn constructs a graph using a _graph builder_ ,
2019-03-21 19:59:06 -05:00
described in a later section.
## Configuration Loader
The top-level configuration structure is represented by model types in
2023-09-20 06:35:35 -05:00
[package `configs` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/configs ).
2019-03-21 19:59:06 -05:00
A whole configuration (the root module plus all of its descendent modules)
is represented by
2023-09-20 06:35:35 -05:00
[`configs.Config` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/configs#Config ).
2019-03-21 19:59:06 -05:00
The `configs` package contains some low-level functionality for constructing
configuration objects, but the main entry point is in the sub-package
2023-09-20 06:35:35 -05:00
[`configload` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/configs/configload] ),
2019-03-21 19:59:06 -05:00
via
2023-09-20 06:35:35 -05:00
[`configload.Loader` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/configs/configload#Loader ).
2019-03-21 19:59:06 -05:00
A loader deals with all of the details of installing child modules
2023-09-21 04:53:02 -05:00
(during `tofu init` ) and then locating those modules again when a
2019-03-21 19:59:06 -05:00
configuration is loaded by a backend. It takes the path to a root module
and recursively loads all of the child modules to produce a single
2023-09-20 06:35:35 -05:00
[`configs.Config` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/configs#Config )
2019-03-21 19:59:06 -05:00
representing the entire configuration.
2023-09-21 04:53:02 -05:00
OpenTofu expects configuration files written in the OpenTofu language, which
2019-03-21 19:59:06 -05:00
is a DSL built on top of
2019-09-09 17:58:44 -05:00
[HCL ](https://github.com/hashicorp/hcl ). Some parts of the configuration
2019-03-21 19:59:06 -05:00
cannot be interpreted until we build and walk the graph, since they depend
on the outcome of other parts of the configuration, and so these parts of
the configuration remain represented as the low-level HCL types
2021-02-24 07:32:08 -06:00
[`hcl.Body` ](https://pkg.go.dev/github.com/hashicorp/hcl/v2/#Body )
2019-03-21 19:59:06 -05:00
and
2021-02-24 07:32:08 -06:00
[`hcl.Expression` ](https://pkg.go.dev/github.com/hashicorp/hcl/v2/#Expression ),
2023-09-21 04:53:02 -05:00
allowing OpenTofu to interpret them at a more appropriate time.
2019-03-21 19:59:06 -05:00
## State Manager
2019-03-21 20:18:28 -05:00
A _state manager_ is responsible for storing and retrieving snapshots of the
2023-09-21 04:53:02 -05:00
[OpenTofu state ](https://opentofu.org/docs/language/state/index.html )
2019-03-21 19:59:06 -05:00
for a particular workspace. Each manager is an implementation of
2019-03-21 20:18:28 -05:00
some combination of interfaces in
2023-09-20 06:35:35 -05:00
[the `statemgr` package ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/states/statemgr ),
2019-03-21 20:18:28 -05:00
with most practical managers implementing the full set of operations
described by
2023-09-20 06:35:35 -05:00
[`statemgr.Full` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/states/statemgr#Full )
2019-03-21 20:18:28 -05:00
provided by a _backend_ . The smaller interfaces exist primarily for use in
other function signatures to be explicit about what actions the function might
take on the state manager; there is little reason to write a state manager
that does not implement all of `statemgr.Full` .
2019-03-21 19:59:06 -05:00
The implementation
2023-09-20 06:35:35 -05:00
[`statemgr.Filesystem` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/states/statemgr#Filesystem ) is used
2019-03-21 19:59:06 -05:00
by default (by the `local` backend) and is responsible for the familiar
2023-09-21 04:53:02 -05:00
`terraform.tfstate` local file that most OpenTofu users start with, before
they switch to [remote state ](https://opentofu.org/docs/language/state/remote ).
2019-03-21 20:18:28 -05:00
Other implementations of `statemgr.Full` are used to implement remote state.
2019-03-21 19:59:06 -05:00
Each of these saves and retrieves state via a remote network service
appropriate to the backend that creates it.
2019-03-21 20:18:28 -05:00
A state manager accepts and returns a state snapshot as a
2023-09-20 06:35:35 -05:00
[`states.State` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/states#State )
2019-03-21 19:59:06 -05:00
object. The state manager is responsible for exactly how that object is
serialized and stored, but all state managers at the time of writing use
the same JSON serialization format, storing the resulting JSON bytes in some
kind of arbitrary blob store.
## Graph Builder
A _graph builder_ is called by a
2023-10-12 06:11:01 -05:00
[`tofu.Context` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/tofu#Context )
2019-03-21 19:59:06 -05:00
method (e.g. `Plan` or `Apply` ) to produce the graph that will be used
to represent the necessary steps for that operation and the dependency
relationships between them.
In most cases, the
2023-09-21 04:53:02 -05:00
[vertices ](https://en.wikipedia.org/wiki/Vertex_(graph_theory )) of OpenTofu's
2019-03-21 19:59:06 -05:00
graphs each represent a specific object in the configuration, or something
derived from those configuration objects. For example, each `resource` block
in the configuration has one corresponding
2023-09-21 04:53:02 -05:00
[`GraphNodeConfigResource` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/tofu#GraphNodeConfigResource )
vertex representing it in the "plan" graph. (OpenTofu Core uses terminology
2021-02-24 07:32:08 -06:00
inconsistently, describing graph _vertices_ also as graph _nodes_ in various
2019-03-21 19:59:06 -05:00
places. These both describe the same concept.)
The [edges ](https://en.wikipedia.org/wiki/Glossary_of_graph_theory_terms#edge )
in the graph represent "must happen after" relationships. These define the
order in which the vertices are evaluated, ensuring that e.g. one resource is
created before another resource that depends on it.
Each operation has its own graph builder, because the graph building process
is different for each. For example, a "plan" operation needs a graph built
directly from the configuration, but an "apply" operation instead builds its
graph from the set of changes described in the plan that is being applied.
The graph builders all work in terms of a sequence of _transforms_ , which
are implementations of
2023-10-12 06:11:01 -05:00
[`tofu.GraphTransformer` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/tofu#GraphTransformer ).
2019-03-21 19:59:06 -05:00
Implementations of this interface just take a graph and mutate it in any
way needed, and so the set of available transforms is quite varied. Some
2021-02-24 07:32:08 -06:00
important examples include:
2019-03-21 19:59:06 -05:00
2023-09-21 04:53:02 -05:00
* [`ConfigTransformer` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/tofu#ConfigTransformer ),
2019-03-21 19:59:06 -05:00
which creates a graph vertex for each `resource` block in the configuration.
2023-09-21 04:53:02 -05:00
* [`StateTransformer` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/tofu#StateTransformer ),
2019-03-21 19:59:06 -05:00
which creates a graph vertex for each resource instance currently tracked
in the state.
2023-09-21 04:53:02 -05:00
* [`ReferenceTransformer` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/tofu#ReferenceTransformer ),
2019-03-21 19:59:06 -05:00
which analyses the configuration to find dependencies between resources and
other objects and creates any necessary "happens after" edges for these.
2023-09-21 04:53:02 -05:00
* [`ProviderTransformer` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/tofu#ProviderTransformer ),
2019-03-21 19:59:06 -05:00
which associates each resource or resource instance with exactly one
provider configuration (implementing
2023-09-21 04:53:02 -05:00
[the inheritance rules ](https://opentofu.org/docs/language/providers/ ))
2019-03-21 19:59:06 -05:00
and then creates "happens after" edges to ensure that the providers are
initialized before taking any actions with the resources that belong to
them.
There are many more different graph transforms, which can be discovered
2019-03-21 20:18:28 -05:00
by reading the source code for the different graph builders. Each graph
2019-03-21 19:59:06 -05:00
builder uses a different subset of these depending on the needs of the
operation that is being performed.
The result of graph building is a
2023-10-12 06:11:01 -05:00
[`tofu.Graph` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/tofu#Graph ), which
2019-03-21 19:59:06 -05:00
can then be processed using a _graph walker_ .
## Graph Walk
The process of walking the graph visits each vertex of that graph in a way
which respects the "happens after" edges in the graph. The walk algorithm
itself is implemented in
2023-09-20 06:35:35 -05:00
[the low-level `dag` package ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/dag#AcyclicGraph.Walk )
2019-03-21 19:59:06 -05:00
(where "DAG" is short for [_Directed Acyclic Graph_ ](https://en.wikipedia.org/wiki/Directed_acyclic_graph )), in
2023-09-20 06:35:35 -05:00
[`AcyclicGraph.Walk` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/dag#AcyclicGraph.Walk ).
2023-09-21 04:53:02 -05:00
However, the "interesting" OpenTofu walk functionality is implemented in
2023-10-12 06:11:01 -05:00
[`tofu.ContextGraphWalker` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/tofu#ContextGraphWalker ),
2019-03-21 19:59:06 -05:00
which implements a small set of higher-level operations that are performed
during the graph walk:
* `EnterPath` is called once for each module in the configuration, taking a
module address and returning a
2023-10-12 06:11:01 -05:00
[`tofu.EvalContext` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/tofu#EvalContext )
that tracks objects within that module. `tofu.Context` is the _global_
context for the entire operation, while `tofu.EvalContext` is a
2019-03-21 19:59:06 -05:00
context for processing within a single module, and is the primary means
by which the namespaces in each module are kept separate.
Each vertex in the graph is evaluated, in an order that guarantees that the
"happens after" edges will be respected. If possible, the graph walk algorithm
will evaluate multiple vertices concurrently. Vertex evaluation code must
therefore make careful use of concurrency primitives such as mutexes in order
2019-03-21 20:18:28 -05:00
to coordinate access to shared objects such as the `states.State` object.
In most cases, we use the helper wrapper
2023-09-20 06:35:35 -05:00
[`states.SyncState` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/states#SyncState )
2019-03-21 20:18:28 -05:00
to safely implement concurrent reads and writes from the shared state.
2019-03-21 19:59:06 -05:00
## Vertex Evaluation
2019-03-21 20:18:28 -05:00
The action taken for each vertex during the graph walk is called
2021-02-24 15:19:55 -06:00
_execution_. Execution runs a sequence of arbitrary actions that make sense
2019-03-21 20:18:28 -05:00
for a particular vertex type.
2019-03-21 19:59:06 -05:00
For example, evaluation of a vertex representing a resource instance during
a plan operation would include the following high-level steps:
* Retrieve the resource's associated provider from the `EvalContext` . This
should already be initialized earlier by the provider's own graph vertex,
due to the "happens after" edge between the resource node and the provider
node.
* Retrieve from the state the portion relevant to the specific resource
instance being evaluated.
* Evaluate the attribute expressions given for the resource in configuration.
This often involves retrieving the state of _other_ resource instances so
that their values can be copied or transformed into the current instance's
attributes, which is coordinated by the `EvalContext` .
* Pass the current instance state and the resource configuration to the
provider, asking the provider to produce an _instance diff_ representing the
differences between the state and the configuration.
* Save the instance diff as part of the plan that is being constructed by
this operation.
2021-02-24 15:19:55 -06:00
Each execution step for a vertex is an implementation of
2023-10-12 06:11:01 -05:00
[`tofu.Execute` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/erraform#Execute ).
2019-03-21 19:59:06 -05:00
As with graph transforms, the behavior of these implementations varies widely:
2021-02-24 15:19:55 -06:00
whereas graph transforms can take any action against the graph, an `Execute`
2019-03-21 19:59:06 -05:00
implementation can take any action against the `EvalContext` .
2023-10-12 06:11:01 -05:00
The implementation of `tofu.EvalContext` used in real processing
2019-03-21 19:59:06 -05:00
(as opposed to testing) is
2023-10-12 06:11:01 -05:00
[`tofu.BuiltinEvalContext` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/tofu#BuiltinEvalContext ).
2019-03-21 19:59:06 -05:00
It provides coordinated access to plugins, the current state, and the current
plan via the `EvalContext` interface methods.
2021-02-24 15:19:55 -06:00
In order to be executed, a vertex must implement
2023-10-12 06:11:01 -05:00
[`tofu.GraphNodeExecutable` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/tofu#GraphNodeExecutable ),
2021-02-24 15:19:55 -06:00
which has a single `Execute` method that handles. There are numerous `Execute`
implementations with different behaviors, but some prominent examples are:
2023-09-21 04:53:02 -05:00
* [NodePlannableResource.Execute ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/tofu#NodePlannableResourceInstance.Execute ), which handles the `plan` operation.
2021-02-24 15:19:55 -06:00
2023-09-21 04:53:02 -05:00
* [`NodeApplyableResourceInstance.Execute` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/tofu#NodeApplyableResourceInstance.Execute ), which handles the main `apply` operation.
2021-02-24 15:19:55 -06:00
2023-09-21 04:53:02 -05:00
* [`NodeDestroyResourceInstance.Execute` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/tofu#EvalWriteState ), which handles the main `destroy` operation.
2021-02-24 15:19:55 -06:00
A vertex must complete successfully before the graph walk will begin evaluation
for other vertices that have "happens after" edges. Evaluation can fail with one
or more errors, in which case the graph walk is halted and the errors are
returned to the user.
2019-03-21 19:59:06 -05:00
### Expression Evaluation
An important part of vertex evaluation for most vertex types is evaluating
any expressions in the configuration block associated with the vertex. This
completes the processing of the portions of the configuration that were not
processed by the configuration loader.
2019-03-21 20:18:28 -05:00
The high-level process for expression evaluation is:
2019-03-21 19:59:06 -05:00
2019-03-21 20:18:28 -05:00
1. Analyze the configuration expressions to see which other objects they refer
2019-03-21 19:59:06 -05:00
to. For example, the expression `aws_instance.example[1]` refers to one of
the instances created by a `resource "aws_instance" "example"` block in
2019-03-21 20:18:28 -05:00
configuration. This analysis is performed by
2023-09-20 06:35:35 -05:00
[`lang.References` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/lang#References ),
2019-03-21 20:18:28 -05:00
or more often one of the helper wrappers around it:
2023-09-20 06:35:35 -05:00
[`lang.ReferencesInBlock` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/lang#ReferencesInBlock )
2019-03-21 20:18:28 -05:00
or
2023-09-20 06:35:35 -05:00
[`lang.ReferencesInExpr` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/lang#ReferencesInExpr )
2019-03-21 20:18:28 -05:00
2021-02-24 07:32:08 -06:00
1. Retrieve from the state the data for the objects that are referred to and
2019-03-21 19:59:06 -05:00
create a lookup table of the values from these objects that the
HCL evaluation code can refer to.
2021-02-24 07:32:08 -06:00
1. Prepare the table of built-in functions so that HCL evaluation can refer to
2019-03-21 19:59:06 -05:00
them.
2021-02-24 07:32:08 -06:00
1. Ask HCL to evaluate each attribute's expression (a
[`hcl.Expression` ](https://pkg.go.dev/github.com/hashicorp/hcl/v2/#Expression )
object) against the data and function lookup tables.
2019-03-21 19:59:06 -05:00
2019-03-21 20:18:28 -05:00
In practice, steps 2 through 4 are usually run all together using one
2023-09-20 06:35:35 -05:00
of the methods on [`lang.Scope` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/lang#Scope );
2019-03-21 20:18:28 -05:00
most commonly,
2023-09-20 06:35:35 -05:00
[`lang.EvalBlock` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/lang#Scope.EvalBlock )
2019-03-21 20:18:28 -05:00
or
2023-09-20 06:35:35 -05:00
[`lang.EvalExpr` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/lang#Scope.EvalExpr ).
2019-03-21 20:18:28 -05:00
Expression evaluation produces a dynamic value represented as a
2021-02-24 07:32:08 -06:00
[`cty.Value` ](https://pkg.go.dev/github.com/zclconf/go-cty/cty#Value ).
2023-09-21 04:53:02 -05:00
This Go type represents values from the OpenTofu language and such values
2019-03-21 20:18:28 -05:00
are eventually passed to provider plugins.
2019-03-21 19:59:06 -05:00
### Sub-graphs
Some vertices have a special additional behavior that happens after their
evaluation steps are complete, where the vertex implementation is given
the opportunity to build another separate graph which will be walked as part
of the evaluation of the vertex.
The main example of this is when a `resource` block has the `count` argument
set. In that case, the plan graph initially contains one vertex for each
`resource` block, but that graph then _dynamically expands_ to have a sub-graph
containing one vertex for each instance requested by the count. That is, the
sub-graph of `aws_instance.example` might contain vertices for
`aws_instance.example[0]` , `aws_instance.example[1]` , etc. This is necessary
because the `count` argument may refer to other objects whose values are not
known when the main graph is constructed, but become known while evaluating
other vertices in the main graph.
This special behavior applies to vertex objects that implement
2023-10-12 06:11:01 -05:00
[`tofu.GraphNodeDynamicExpandable` ](https://pkg.go.dev/github.com/opentofu/opentofu/internal/tofu#GraphNodeDynamicExpandable ).
2021-02-24 07:32:08 -06:00
Such vertices have their own nested _graph builder_ , _graph walk_ ,
2019-03-21 19:59:06 -05:00
and _vertex evaluation_ steps, with the same behaviors as described in these
sections for the main graph. The difference is in which graph transforms
are used to construct the graph and in which evaluation steps apply to the
nodes in that sub-graph.