Property-graph model (Node + Edge) — M1 spike for #43#44
Merged
Conversation
Prototype of the M1 changeset from RFC #43: collapse the NetBox-inspired per-kind hierarchy into a property graph of typed nodes and edges, both carrying key/value attribute bags validated against a schema registry. New v1alpha2 kinds: - Node — graph vertex; spec.type names its asset class (Region, Site, Host [the former compute Node], ...), spec.attributes its data. - Edge — directed relationship; spec.type names the relationship class (located-in, member-of, ...), with from/to endpoints + attributes. - NodeType — closed attribute schema for a class of nodes. - EdgeType — closed attribute schema + endpoint-type constraints for edges. Validation (internal/graph) is shared between admission webhooks and reconcilers: attributes are checked against the NodeType/EdgeType schema (unknown keys, missing-required, type/enum parsing); edges verify endpoint existence and endpoint-type constraints. The Node DELETE webhook is a generic delete-guard — one Edge-endpoint field indexer replaces the per-kind reference indexers of v1alpha1. The graph kinds use group graph.inventory.miloapis.com so the prototype installs side-by-side with v1alpha1, whose `Node` kind would otherwise collide at the CRD level (the very collision the RFC resolves via type: Host). The production migration reclaims inventory.miloapis.com after v1alpha1 removal. Not in scope for this prototype: envtest suite wiring, IAM ProtectedResource/ Roles, topology-label propagation, CR migration tooling (M2). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Register the v1alpha2 scheme, graph indexers, graph reconcilers, and graph webhooks in the controller envtest suite so the property-graph model is exercised against a real apiserver. Adds graph_controller_test.go covering: - Node Ready when NodeType exists and attributes validate - Node admission rejects: missing NodeType, unknown attribute, missing required attribute, non-parsing Integer, out-of-enum String - Edge Ready + EndpointsResolved when both endpoints exist - Edge admission rejects: missing endpoint Node, endpoint-type-constraint violation - Node DELETE blocked while an Edge references it (generic delete-guard) Also fixes the Edge distinct-endpoints CEL rule: structs are not comparable with `!=`, so compare self.from.name != self.to.name. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
Author
|
imma do datum-cloud/inventory#9 next |
privateip
approved these changes
Jun 12, 2026
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.
Prototype of the M1 changeset from RFC #43 (collapse the NetBox-inspired per-kind hierarchy into a property graph). Tracking enhancement: datum-cloud/enhancements#764.
What this is
A working, envtest-covered prototype of the graph model: typed nodes and edges, both carrying key/value attributes validated against a schema registry.
New
v1alpha2kinds (api/v1alpha2/)Node— graph vertex.spec.typenames the asset class (Site,Host[the former compute Node], …),spec.attributesholds its data. Type immutable.Edge— directed relationship.spec.type(located-in,member-of, …) +from/to+ attributes. Type immutable; endpoints distinct (CEL).NodeType/EdgeType— closed attribute schemas (key/type/required/enum); EdgeType also constrains endpoint node-types.Validation (
internal/graph/)Shared between admission webhooks and reconcilers: unknown-key reject, missing-required, Integer/Float/Boolean parse, String enum; edges check endpoint existence + endpoint-type constraints. Node DELETE is a generic delete-guard — one Edge-endpoint field indexer replaces the per-kind reference indexers of v1alpha1.
Key decision — group name
The RFC's collision is real at the CRD level: kind
Nodecan't carry two incompatible schemas under one group without a conversion webhook. So the prototype uses groupgraph.inventory.miloapis.com→ installs side-by-side with v1alpha1. The production migration reclaimsinventory.miloapis.comonce v1alpha1 is removed (per RFC, compute node →type: Host).Tests
internal/controller/graph_controller_test.go(envtest): Node/Edge happy paths, attribute-schema rejections (unknown / missing-required / bad-type / bad-enum), edge endpoint-existence + endpoint-type-constraint rejections, and the Node delete-guard. Full suite green (63 specs).Explicitly out of scope (M2 / follow-ups)
ProtectedResource+ Roles for graph kinds (CLAUDE.md step 10).datumctl-inventorytype-aware listing to recover per-kind print columns — tracked in Make datumctl inventory plugin type-aware for the property-graph model (Node/Edge) datum-cloud/inventory#9.🤖 Generated with Claude Code