You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
edgeKind = "attachesTo" orders deletes producer-first, which breaks teardown for resources whose cloud enforces referential integrity (delete the referencer before the referenced). This surfaced via a new conformance test for GCP::Compute::UrlMap (RFC-0043 annotated the whole GCE LB chain with attachesTo).
Opening for discussion on whether the fix belongs in the GCP schema, in core, or both.
Comment L229-230 documents this ("the producer is deleted first"), and L363-364 notes attachesTo has no effect on create (it only inverts destroy). So the behavior is intentional/self-consistent — the question is whether the direction is right.
Why it breaks GCP
GCP enforces referential integrity across the LB chain:
Each referencer must be deleted before what it references. With attachesTo, formae deletes e.g. the BackendService before the UrlMap that still points at it → GCP returns resourceInUseByAnotherResource → Destroy fails and cascades.
Confirmed by conformance: UrlMap with defaultService on attachesTo fails Destroy; switching that field to the default edgeKind makes the full lifecycle pass.
Cross-check: AWS plugin
formae-plugin-aws uses no edgeKind/attachesTo anywhere. The analogous ELBv2 chain (elasticloadbalancingv2/listener.pkl: loadBalancerArn, defaultActions[].targetGroupArn) and deeper chains (API Gateway RestApi → Resource → Method → Deployment/Stage) use plain String|formae.Resolvable references → default (consumer-first) edge → create and destroy cleanly. No producer-first case exists in that plugin.
Observation
attachesTo's only effect is producer-first destroy. For reference fields under referential integrity that is never valid (the referencer must go first), and the name "X attaches to Y" intuitively reads as "detach X first" (consumer-first) — opposite to the implementation. No plugin currently relies on producer-first ordering.
Options
Schema (plugin): change the GCP LB reference fields from attachesTo to default. (Done for UrlMap in formae-plugin-gcp PR fix: update expected values of e2e tests #68; remaining chain — target proxies, forwarding rules, regionUrlMap — pending this discussion.)
Core: if attachesTo was intended to mean consumer-first (or if producer-first has no real use case), correct the direction / semantics in changeset.go.
What was attachesTo intended for? Is there a resource relationship where producer-first destroy is correct (e.g. host-deletion auto-cleans an attachment)? That determines whether this is a schema mis-annotation or a core direction bug.
Summary
edgeKind = "attachesTo"orders deletes producer-first, which breaks teardown for resources whose cloud enforces referential integrity (delete the referencer before the referenced). This surfaced via a new conformance test forGCP::Compute::UrlMap(RFC-0043 annotated the whole GCE LB chain withattachesTo).Opening for discussion on whether the fix belongs in the GCP schema, in core, or both.
Mechanic
internal/metastructure/changeset/changeset.go,buildDeleteDependencies:EdgeKindDefault(L344-347):depNode.LinkWith(dependentGroup)→ consumer deleted first, producer second.EdgeKindAttachesTo(L305-308):dependentGroup.LinkWith(depNode)→ consumer waits for producer → producer deleted first, consumer second.attachesTohas no effect on create (it only inverts destroy). So the behavior is intentional/self-consistent — the question is whether the direction is right.Why it breaks GCP
GCP enforces referential integrity across the LB chain:
Each referencer must be deleted before what it references. With
attachesTo, formae deletes e.g. the BackendService before the UrlMap that still points at it → GCP returnsresourceInUseByAnotherResource→ Destroy fails and cascades.Confirmed by conformance:
UrlMapwithdefaultServiceonattachesTofails Destroy; switching that field to the default edgeKind makes the full lifecycle pass.Cross-check: AWS plugin
formae-plugin-awsuses noedgeKind/attachesToanywhere. The analogous ELBv2 chain (elasticloadbalancingv2/listener.pkl:loadBalancerArn,defaultActions[].targetGroupArn) and deeper chains (API GatewayRestApi → Resource → Method → Deployment/Stage) use plainString|formae.Resolvablereferences → default (consumer-first) edge → create and destroy cleanly. No producer-first case exists in that plugin.Observation
attachesTo's only effect is producer-first destroy. For reference fields under referential integrity that is never valid (the referencer must go first), and the name "X attaches to Y" intuitively reads as "detach X first" (consumer-first) — opposite to the implementation. No plugin currently relies on producer-first ordering.Options
attachesTotodefault. (Done forUrlMapin formae-plugin-gcp PR fix: update expected values of e2e tests #68; remaining chain — target proxies, forwarding rules, regionUrlMap — pending this discussion.)attachesTowas intended to mean consumer-first (or if producer-first has no real use case), correct the direction / semantics inchangeset.go.What was
attachesTointended for? Is there a resource relationship where producer-first destroy is correct (e.g. host-deletion auto-cleans an attachment)? That determines whether this is a schema mis-annotation or a core direction bug.