Repository navigation
Conversation
References through `local.*` were dropped when collecting dependencies,
so a resource using `compartment_id = local.compartment_id` (where the
local reads a data source or another resource) got no edge. For configs
that route values through locals, the graph was mostly disconnected:
`oxid graph` under-reported dependencies and plan/apply ordering missed
real ones.
- Keep `local.<name>` references (expressions and `${}` in nested blocks)
- Resolve each local to the resource and data source addresses it
reaches, following locals that reference other locals; cycles between
locals are cut instead of looping
- Expand local references for resource, data source and output edges
- Include references in `count` and `for_each`, not only attributes
- Fix data source DOT labels, which were prefixed twice (`data.data.`)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The DAG builder evaluates count and for_each with variables only. When they depend on locals, resources or data sources (e.g. `count = length(local.dbs)`), the expression evaluated against nulls: length() returned 0 and toset() an empty set, so the resource got zero instances and silently disappeared from the graph. Treat such expressions as not statically known and keep the resource as a single unindexed node, as is already done when for_each evaluates to null. Its dependencies are still tracked through the count/for_each references. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4 of 5 tasks
Contributor
|
@ftgonc approved workflows |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
collect_referencesskipslocal.*, so any dependency that goes through a local value is lost. A resource withcompartment_id = local.compartment_id, where the local reads a data source, gets no edge to that data source. Configs that route values through locals (very common) end up with a mostly disconnected resource graph:oxid graphunder-reports dependencies, and plan/apply ordering misses real ones.local.<name>references, both in expressions and in${…}interpolations inside nested blocksresolve_local_references: resolve each local to the resource and data source addresses it reaches, following locals that reference other locals. Cycles between locals are cut instead of loopingcountandfor_each, not only from attributes (e.g.for_each = local.endpoints)count/for_eachdepends on locals, resources or data sources. The DAG builder evaluates these with variables only, socount = length(local.dbs)evaluated to 0 (andtoset(local.ids)to an empty set) and the resource silently disappeared from the graph. Such resources are now a single unindexed node, as already happens whenfor_eachevaluates to null; their dependencies are still trackedto_dot, which were prefixed twice (data.data.x.y) because the address already includesdata.var.*,each.*,count.*,path.*,terraform.*andselfare still ignored, as before.Known gaps (not in this PR)
lifecycle { precondition / postcondition }blocks aren't parsed (LifecycleConfighas no field for them), so references inside them don't create edges. Terraform does count themmodule.*references are still opaquecount/for_eachcan't be evaluated at graph time is one unindexed node, so its instances aren't individually addressable in the graph. That's the existing behaviour for unresolvablefor_each, now applied consistently; previously it had no node at allTest plan
tests/resource_graph_test.rs: local → data source (direct attribute and map attribute), chained locals through aforexpression,for_each = local.x, output referencing a local, cyclic locals (no hang, no edges),varthrough a local (still no edge),count = length(local.x)andfor_each = toset(local.x)keep the resource,count = var.nstill expands, singledata.prefix in DOT labelscargo fmt --all -- --checkcleancargo clippy --all-targets -- -D warnings: no new findings. Current stable clippy reports 33 pre-existingdouble_must_useerrors insrc/state/backend.rsonmainas well, untouched hereoxid graphwent from 5 to 41 edges, and 34 of the 41 dependencies Terraform records in state are now reachable in the graph (previously almost none). At least one of the remaining 7 comes from alifecycleprecondition. On another config, 5 resources withcount = length(local.…)that were missing from the graph now appear. No cycles were introduced on any of the six configurations tried