Skip to content

edgeKind=attachesTo deletes producer-first, breaking GCP LB chain teardown #519

Description

@naxty

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 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.

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.
  • 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:

ForwardingRule -> TargetProxy -> UrlMap -> BackendService -> HealthCheck

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

  1. 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.)
  2. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions