Terraform preserves dependencies between counted instances
Terraform 0.7.13 repairs dependency recording in its experimental graph and fixes a Lambda crash caused by an absent environment.
A dependency between two instances of one resource can look like a resource depending on itself if the graph loses the instance index. Terraform 0.7.13 fixes precisely that distinction in its new graph implementation. An instance at index two can depend on the instance at index zero, and the saved state needs to retain that relationship. The tagged release notes date the release to November 23 and describe the repair as recording dependencies for explicit self references.
The phrase needs some care. This change does not make an arbitrary circular dependency meaningful. The implementation and regression test in pull request 10319 concern separate instances produced by a counted resource. Mitchell Hashimoto's patch explains that a dependency such as foo.bar.2 depending on foo.bar.0 was missing from state. The declaration has one resource name, but its expanded instances have distinct addresses.
I value Terraform's ability to express infrastructure relationships through a common configuration language. That abstraction depends on the implementation retaining distinctions that the configuration makes. An index lost while recording dependencies is a small code defect with consequences for how accurately state describes the managed resources.
The missing index
The repair changes the construction of graphNodeExpandedResource inside NodeApplyableResource.EvalTree. Previously the temporary object received the resource configuration alone. The patch also supplies addr.Index before calling StateDependencies(). The existing dependency calculation therefore receives the identity of the particular expanded instance.
This is a useful detail because it locates the defect. Terraform already has an instance address at this point in the new apply graph. The problem is that the adapter into an older dependency calculation discarded part of that address. Repairing the adapter allows the existing calculation to distinguish a reference to the current instance from a reference to a sibling instance.
The regression test makes the intended state concrete. It creates three instances through a mock provider and uses a mock provisioner containing a reference to instance zero. The expected state includes these relationships, shown here as an abbreviated rendering of the test's output.
aws_instance.foo.1:
Dependencies:
aws_instance.foo.0
aws_instance.foo.2:
Dependencies:
aws_instance.foo.0
The fixture is an internal test configuration. Its mock shell provisioner and artificial resource attributes are not a deployable AWS example. What matters for an operator reading the test is the expected state. Instances one and two retain a dependency on zero, while zero does not acquire a dependency on itself.
The test also checks that the provisioner ran for all three instances. It sorts the collected instance identifiers before comparing them, so that assertion does not establish a total execution order. The state assertion is the direct evidence for the dependency-recording repair. Reading the test this way avoids attributing a stronger scheduling guarantee to it than it actually checks.
An experimental graph approaching wider use
The surrounding release history explains why this fix appears in a maintenance release. The same tagged changelog records experimental apply and destroy graphs in 0.7.8, followed by an experimental plan graph in 0.7.10. Those entries describe work intended for 0.8 and expose command-line flags for trying it in the 0.7 series.
Several earlier entries concern relationships that a graph rewrite can mishandle. The 0.7.10 notes mention avoiding loops for destroy nodes that reference themselves. The 0.7.11 notes describe proper edges through module outputs in the new destroy graph. These are separate fixes, but they establish the immediate context for 0.7.13. Graph construction is changing while Terraform preserves the meaning of existing configurations.
For someone evaluating that experimental implementation, the practical significance is specific. A successful apply is insufficient evidence that all relationships reached the saved state. The new regression test examines the resulting dependency information explicitly. That is the appropriate level of observation for a bug in recording dependencies, even when the configuration itself appears to work.
My preference is for changes like this to have a narrow, inspectable explanation. Supplying the missing index makes the patch easy to connect to its test. It also keeps the discussion about the relationship Terraform failed to represent, without suggesting that every dependency problem has the same cause.
An absent Lambda environment
The release has one other listed fix, for an AWS Lambda function whose environment is absent. The Lambda patch explains that the environment pointer can be nil when a function has never had an environment applied. Previously, the read path accessed function.Environment.Variables before passing the variables to a flattening helper. That access could crash before the helper had any opportunity to handle the absence.
The corrected call passes the environment response itself. The helper checks for nil and returns before reading its variables. An added acceptance-test step starts with a basic function configuration and checks that the environment collection has zero elements. This covers the transition from a function without environment variables to the existing test configuration with them.
Both fixes concern information that an intermediate representation failed to preserve. The graph adapter omitted an instance index. The Lambda read path assumed an optional response object existed. Their repairs remain distinct, and each has a test directed at its own failure. For this release, the useful operational detail is that counted-instance dependencies reach state and Lambda reads accept the absence of an environment object.