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
This is a sketch to anchor discussion and to spawn the per-milestone implementation issues hung off the enhancement. It is intentionally incremental: each milestone is independently shippable and keeps the prototype running.
Where we are today
The service already ships these cluster-scoped CRDs in inventory.miloapis.com/v1alpha1, each with a controller, a validating webhook, generated CRDs/RBAC under config/, and SetupIndexers wiring:
Kind
Models
Key refs
Region
geographic grouping
—
Site
facility / AZ / edge / virtual location
regionRef
Cluster
a Kubernetes cluster footprint
controlPlaneSiteRef
Node
physical/virtual host, hardware, addresses
siteRef, assignment→cluster
NetworkDevice
router/switch/firewall
clusterRef, siteRef
Link
logical/physical/internet link between two assets
endpoints[2] (AssetReference)
Shared building blocks already exist and should be reused, not reinvented:
LocalObjectReference{Name} and AssetReference{Kind,Name} for references.
Coordinates, and the topology.inventory.miloapis.com/* label convention for query/rollup.
Per-kind validating webhooks enforcing immutability and cross-ref existence (e.g. NetworkDevice.siteRef must match its Cluster.siteRef).
Gap analysis vs. enhancement goals
Enhancement goal
Covered by
Gap to build
Provider relationships + contract metadata + service IDs
Referenced by Site (who runs the facility), Circuit, and VirtualMachine.
Rack
RackSpec:
siteRef LocalObjectReference (required, immutable)
cage string # free-form; cage/row kept as attributes, not separate kinds
row string
name string
heightU int32 # rack units available
powerFeeds []{ name, phase, voltage, ampsRated }
Cage and row are modeled as fields rather than their own CRDs to avoid kind explosion; promote to kinds only if hierarchy needs independent lifecycle/RBAC.
Placement (embedded, not a kind)
Add an optional Placement to Node and NetworkDevice specs:
Placement:
rackRef LocalObjectReference
startUnit int32 # lowest occupied U
unitHeight int32
face enum: Front|Rear
Webhook validates the U-range fits the rack and does not overlap another device in the same rack/face.
Port
PortSpec:
deviceRef AssetReference (Node|NetworkDevice|Rack-PDU/patch-panel)
type enum: Power|Serial|Ethernet|Optical|PatchPanel
name string # "eth0", "PSU1", "pp-A-24"
speed optional # Quantity, for network ports
Ports are the near/far-end identifiers cabling connects.
Cable (physical layer; distinct from logical Link)
Keep Link for logical/capacity/latency relationships; Cable records the physical run between two Ports. A Link may reference the Cable(s) realizing it.
Circuit
CircuitSpec:
providerRef LocalObjectReference
type enum: CrossConnect|ProviderCircuit|Transit|Peering
circuitID string # provider's circuit/LOA id
bandwidthMbps optional int64
aEnd PortReference|SiteReference
zEnd PortReference|SiteReference
serviceRef optional ObjectReference # cross-group, e.g. networking Galactic VPC uplink
Cross-connects are a Circuittype rather than a separate kind.
Models assignment + allocation only. Power state / health are explicit non-goals.
Cross-cutting: typed cross-group reference
Add an ObjectReference{APIGroup,Kind,Name,Namespace?} to common_types.go for linking inventory objects to other platform resources (the "provider circuit ↔ Galactic VPC uplink" goal). AssetReference stays for intra-inventory links.
Per-kind engineering checklist (the established pattern)
For each new kind, one PR delivers:
api/v1alpha1/<kind>_types.go + make generate (deepcopy) + make manifests (CRD/RBAC/webhook).
internal/controller/<kind>_controller.go — status conditions, referential-integrity reconcile, finalizers to block orphaning deletes (e.g. cannot delete a Rack with mounted devices).
internal/webhook/v1alpha1/<kind>_webhook.go — enum/immutability/cross-ref validation; wire SetupXWebhookWithManager in cmd/inventory/main.go.
SetupIndexers entries for the new reference fields.
Printer columns + topology labels for query ergonomics.
envtest coverage for webhook + controller.
IAM: ProtectedResource / Role / PolicyBinding for the kind (per milo-iam).
Deployment: new CRDs flow through the existing config/base + milo-integration component and the tiered milo / instance-of-milo / datum-deployment model — no new wiring beyond CRD registration.
Milestones (each becomes an issue hung off enhancements#713)
Audit history: is apiserver audit logging + managedFields sufficient for v1, or do we want the Activity capability (ActivityPolicy + events) from the start? Affects M6 vs. earlier.
Cage/row as fields vs. kinds: fields proposed for leanness — does any consumer need independent RBAC or lifecycle on a cage/row?
Cable vs. Link: confirm we want a distinct physical Cable kind rather than overloading Link with media/near-far-end fields.
Project association on VMs: reference resourcemanager.miloapis.comProject directly, or keep a free-form identifier like Cluster.provider?
Reconciliation/discovery: explicit non-goal for v1 — confirm nothing here should auto-populate from live infra yet.
Implementation plan for datum-cloud/enhancements#713 — Physical inventory for Milo, built atop the existing
inventory.miloapis.comservice in this repo.This is a sketch to anchor discussion and to spawn the per-milestone implementation issues hung off the enhancement. It is intentionally incremental: each milestone is independently shippable and keeps the prototype running.
Where we are today
The service already ships these cluster-scoped CRDs in
inventory.miloapis.com/v1alpha1, each with a controller, a validating webhook, generated CRDs/RBAC underconfig/, andSetupIndexerswiring:RegionSiteregionRefClustercontrolPlaneSiteRefNodesiteRef,assignment→clusterNetworkDeviceclusterRef,siteRefLinkendpoints[2](AssetReference)Shared building blocks already exist and should be reused, not reinvented:
LocalObjectReference{Name}andAssetReference{Kind,Name}for references.Coordinates, and thetopology.inventory.miloapis.com/*label convention for query/rollup.NetworkDevice.siteRefmust match itsCluster.siteRef).Gap analysis vs. enhancement goals
Site(facility)Link(partial)Node(partial)ObjectReference, printer columnsProposed new kinds (all cluster-scoped, group
inventory.miloapis.com/v1alpha1)Provider
Referenced by
Site(who runs the facility),Circuit, andVirtualMachine.Rack
Cage and row are modeled as fields rather than their own CRDs to avoid kind explosion; promote to kinds only if hierarchy needs independent lifecycle/RBAC.
Placement (embedded, not a kind)
Add an optional
PlacementtoNodeandNetworkDevicespecs:Webhook validates the U-range fits the rack and does not overlap another device in the same rack/face.
Port
Ports are the near/far-end identifiers cabling connects.
Cable (physical layer; distinct from logical
Link)Keep
Linkfor logical/capacity/latency relationships;Cablerecords the physical run between twoPorts. ALinkmay reference theCable(s) realizing it.Circuit
Cross-connects are a
Circuittyperather than a separate kind.VirtualMachine
Models assignment + allocation only. Power state / health are explicit non-goals.
Cross-cutting: typed cross-group reference
Add an
ObjectReference{APIGroup,Kind,Name,Namespace?}tocommon_types.gofor linking inventory objects to other platform resources (the "provider circuit ↔ Galactic VPC uplink" goal).AssetReferencestays for intra-inventory links.Per-kind engineering checklist (the established pattern)
For each new kind, one PR delivers:
api/v1alpha1/<kind>_types.go+make generate(deepcopy) +make manifests(CRD/RBAC/webhook).internal/controller/<kind>_controller.go— status conditions, referential-integrity reconcile, finalizers to block orphaning deletes (e.g. cannot delete aRackwith mounted devices).internal/webhook/v1alpha1/<kind>_webhook.go— enum/immutability/cross-ref validation; wireSetupXWebhookWithManagerincmd/inventory/main.go.SetupIndexersentries for the new reference fields.ProtectedResource/Role/PolicyBindingfor the kind (permilo-iam).config/base+milo-integrationcomponent and the tiered milo / instance-of-milo / datum-deployment model — no new wiring beyond CRD registration.Milestones (each becomes an issue hung off enhancements#713)
Provider; addproviderReftoSite.Rack+PlacementonNode/NetworkDevice; overlap-validation webhook.Port,Cable; relateLink→Cable.Circuit(incl. cross-connect) + cross-groupObjectReference; first concrete link to a networking resource.VirtualMachine.Open questions
ActivityPolicy+ events) from the start? Affects M6 vs. earlier.Cablekind rather than overloadingLinkwith media/near-far-end fields.resourcemanager.miloapis.comProjectdirectly, or keep a free-form identifier likeCluster.provider?cc @scotwells (original prototype in #1)