22447 Add Cooling infrastructure modeling#22517
Conversation
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
|
@claude /review Only report on issues of potential concern; we don't need commentary on anything that doesn't require further consideration. Also see comments on previous review of Declined requested changes and reasoning. |
|
Claude finished @arthanson's task in 7m 33s —— View job Code Review — 22447 Add Cooling Infrastructure Modeling
Two issues of concern follow. Items already discussed and declined in the previous review round are not repeated. 1. New conversion functions lack unit tests
These functions are the sole mechanism ensuring denormalized ordering columns are accurate. A regression (wrong conversion factor, wrong branch taken) would silently corrupt ordering and filtering across all cooling objects without any test catching it. 2.
|
|
Both Claude review issues addressed. |
jeremystretch
left a comment
There was a problem hiding this comment.
This is a good start, but let's rethink the data model some. Specifically consider:
- Do we need to model individual hoses? If so, how do we handle multi-point connectors (e.g. a hose with a 1-to-n splitter)?
- Do we need to explicitly model the return path in addition to the supply path?
- What are the canonical types of physical inlet & outlet connectors that we need to capture? Is diameter alone sufficient to convey these?
- What temperature information belongs in the data model vs. observability metrics?
The description in FR #22447 was lifted from an initial feature draft; it probably needs a lot more consideration regarding real-world modeling and constraints. It might help to investigate various real-world cooling distribution implementations and determine how we would optimally model those specific instances in NetBox.
|
Historical related issue #6987 useful for searching etc. |
|
Overall a solid keeping the power-model shape. Most deviations from FR #22447 are reasonable simplifications (several requested in review). Notes below, kept short. Decisions
RDHx notes (for whoever picks it up)
Endorsed simplifications (no change requested)
Documentation suggestions
Deferred but acceptable (noted, not blocking)
|
Corrects a rebase conflict resolution: RestrictedPrimaryKeyRelatedField is not defined/imported; matches the field class used by sibling FK fields in this serializer.
Renumber 0243 -> 0248 and re-parent onto 0247_interface_channels to resolve the migration numbering/dependency collision introduced by rebasing onto feature.
26c7347 to
7665f23
Compare
jeremystretch
left a comment
There was a problem hiding this comment.
I'm unclear on the intended use of CoolingIntake. Is it meant to model the return path of warm coolant from a device back to its originating cooling feed/source, or is it to be used solely for the distribution of cold coolant (and the return path is implied to mirror the cold path)?
|
|
||
| ## Relationship to Power | ||
|
|
||
| The cooling stack deliberately mirrors the [power distribution](./power-tracking.md) model: |
There was a problem hiding this comment.
I'm not sure this is accurate any longer, given that connections among power ports & outlets are represented using cables. I would avoid referencing the power data model, and just present cooling as its own independent entity.
There was a problem hiding this comment.
So not in my data centre but there is certainly scope where the cold (in) and warm (out) may not mirror.
I will add that the in and out feed in my case are not numbered the same so referencing to plumbers I couldn't say connection 22 is a cold and warm.
|
|
||
| ## Cooling Sources | ||
|
|
||
| A [cooling source](../models/dcim/coolingsource.md) is the furthest upstream cooling element modeled in NetBox, representing facility plant such as a chiller, cooling tower, dry cooler, or CRAC/CRAH unit. Each source is associated with a site, and may optionally be associated with a particular location within that site. A cooling source is not a device; it represents external facility plant, and records the coolant (fluid type) and total rated cooling capacity for the loops it originates. |
There was a problem hiding this comment.
| A [cooling source](../models/dcim/coolingsource.md) is the furthest upstream cooling element modeled in NetBox, representing facility plant such as a chiller, cooling tower, dry cooler, or CRAC/CRAH unit. Each source is associated with a site, and may optionally be associated with a particular location within that site. A cooling source is not a device; it represents external facility plant, and records the coolant (fluid type) and total rated cooling capacity for the loops it originates. | |
| A [cooling source](../models/dcim/coolingsource.md) is the furthest upstream cooling element modeled in NetBox, representing a chiller, cooling tower, dry cooler, or CRAC/CRAH unit. Each source is associated with a site, and may optionally be associated with a particular location within that site. A cooling source is not a device; it represents external facility plant, and records the coolant (fluid type) and total rated cooling capacity for the loops it originates. |
|
|
||
| ## Cooling Feeds | ||
|
|
||
| A [cooling feed](../models/dcim/coolingfeed.md) represents a coolant loop originating from a cooling source and serving a particular rack. Each feed records an operational status, a rated cooling capacity, and a rated (design) flow rate. |
There was a problem hiding this comment.
| A [cooling feed](../models/dcim/coolingfeed.md) represents a coolant loop originating from a cooling source and serving a particular rack. Each feed records an operational status, a rated cooling capacity, and a rated (design) flow rate. | |
| A [cooling feed](../models/dcim/coolingfeed.md) represents a coolant loop running between a cooling source and a particular rack. Each feed records an operational status, a rated cooling capacity, and a rated (design) flow rate. |
| The [cooling intakes](../models/dcim/coolingintake.md) a feed supplies are not listed on the feed explicitly; they are derived from the devices installed in the rack the feed serves. Moving a device to a different rack therefore reassigns it to that rack's feed automatically. | ||
|
|
There was a problem hiding this comment.
Seems redundant to the section below.
| The [cooling intakes](../models/dcim/coolingintake.md) a feed supplies are not listed on the feed explicitly; they are derived from the devices installed in the rack the feed serves. Moving a device to a different rack therefore reassigns it to that rack's feed automatically. |
| !!! note "Scope of the initial version" | ||
| The cooling model captures topology and design specifications. A few capabilities are intentionally left out at this point: | ||
|
|
||
| - **The return path is implicit.** A single feed models the whole loop; the supply and return legs are not traced as separate objects. | ||
| - **Path tracing and impact analysis are not yet surfaced.** The reference chain supports tracing a loop, but there is no graphical trace or "what does this source feed?" view yet. | ||
| - **Individual hoses are not inventoried.** Connections are modeled as direct references, not as first-class cable objects. | ||
| - **No design pressure or temperature.** These are operating conditions with no stable design value independent of live readings, so they are recorded in a monitoring system rather than in NetBox. |
There was a problem hiding this comment.
The scope of the documentation is limited to what the application currently supports.
| !!! note "Scope of the initial version" | |
| The cooling model captures topology and design specifications. A few capabilities are intentionally left out at this point: | |
| - **The return path is implicit.** A single feed models the whole loop; the supply and return legs are not traced as separate objects. | |
| - **Path tracing and impact analysis are not yet surfaced.** The reference chain supports tracing a loop, but there is no graphical trace or "what does this source feed?" view yet. | |
| - **Individual hoses are not inventoried.** Connections are modeled as direct references, not as first-class cable objects. | |
| - **No design pressure or temperature.** These are operating conditions with no stable design value independent of live readings, so they are recorded in a monitoring system rather than in NetBox. |
| ) | ||
|
|
||
|
|
||
| class PressureUnitChoices(ChoiceSet): |
There was a problem hiding this comment.
Let's remove this if we remove to_kilopascals().
|
|
||
| # Metric | ||
| UNIT_LITERS_PER_MINUTE = 'lpm' | ||
| UNIT_CUBIC_METERS_PER_HOUR = 'm3h' |
There was a problem hiding this comment.
We should arguably include the "p" for consistency with lpm and gpm.
| UNIT_CUBIC_METERS_PER_HOUR = 'm3h' | |
| UNIT_CUBIC_METERS_PER_HOUR = 'm3ph' |
| ### Type | ||
|
|
||
| Indicates whether the outlet carries supply (cold) or return (warm) coolant. | ||
|
|
There was a problem hiding this comment.
I think this is a remnant from an earlier implementation.
| ### Type | |
| Indicates whether the outlet carries supply (cold) or return (warm) coolant. |
| required=False, | ||
| allow_null=True | ||
| ) | ||
| cooling_outflow = serializers.PrimaryKeyRelatedField( |
There was a problem hiding this comment.
This needs to be some form of a nested CoolingOutflowSerializer. (You might need to create a standalone NestedCoolingOutflowSerializer class to resolve the circular dependency.)
|
|
||
| class CoolingIntake(DiameterMixin, MaximumFlowMixin, ModularComponentModel, TrackingModelMixin): | ||
| """ | ||
| A coolant intake/outlet port within a Device (e.g. a server cold-plate inlet or CDU intake). A |
There was a problem hiding this comment.
| A coolant intake/outlet port within a Device (e.g. a server cold-plate inlet or CDU intake). A | |
| A coolant intake port within a Device (e.g. a server cold-plate inlet or CDU intake). A |
Closes: #22447
Adds cooling infrastructure modeling to DCIM, mirroring the shape of the power-distribution stack and reusing the standard NetBox model features (contacts and image attachments on the facility plant, plus change logging, custom fields, and tags). This lets operators model liquid- and hybrid-cooled environments (CDUs, manifolds, RDHx, facility plant) as a source of truth.
NetBox models design intent and physical topology, not live conditions — flow and capacity are design/rated specifications, not telemetry.
The topology parallels power, with two deliberate differences:
Cable/CablePathmachinery; tracing a loop is an FK walk.CoolingFeedrepresents both the supply (cold) and return (warm) paths of a single loop, rather than modeling each direction as a separate feed.End-to-end picture
Coolant connectivity is a chain of direct FKs on the downstream (consuming) side: a
CoolingIntakeis fed by one upstreamCoolingOutflow(CoolingIntake.cooling_outflow), and aCoolingOutflowbelongs to a parentCoolingIntakeon the same device (CoolingOutflow.cooling_intake) — the device takes coolant in through its intake and passes it back out through its outflow. TheCoolingFeedserving a device is derived from the rack the device is installed in, not stored on each intake.In-rack cooling equipment — CDUs, manifolds, and rear-door heat exchangers (RDHx) — is modeled generically as
Devices (typically zero-U) carrying these components, exactly how NetBox models a PDU as a device with power ports/outlets. No bespoke CDU/manifold/RDHx models were added.New models
fluid_typeand a rated cooling capacity. Reuses contacts and image attachments.CoolingOutflow.CoolingIntakeon the same device.Changes to existing models
cooling_method(air / liquid / hybrid / immersion). ADeviceinherits the value from itsDeviceTypeon creation and may override it (likeairflow);DeviceTypeandModuleTypecarry it as a product-level attribute (ModuleTypemirrorsairflow— type-level only, no per-instance override). On the edit and filter forms,cooling_methodandairfloware grouped under a dedicated Cooling section. Each also gains cooling component counter caches (cooling_intake_count/cooling_outflow_count, or the_template_countvariants on the types).cooling_capability(air-only / liquid-capable / liquid-required) andcooling_capacity(kW) defined on the sharedRackBase— set on theRackTypeand propagated to racks (likemax_weight).Cablechanges — coolant connectivity is FK-based (CoolingIntake.cooling_outflow,CoolingOutflow.cooling_intake); no new cable type or cable-termination registration.Field conventions on the new cooling models
Several quantities are modeled as value + unit with a normalized field for correct cross-unit sorting (the same pattern as weight). All are design/rated specifications, not live readings:
DiameterMixin).CoolingFeed.rated_flow_rateandCoolingIntake.maximum_flow— L/min / m³/h / GPM, normalized to L/min (MaximumFlowMixin; the feed inlines the same value/unit/normalized pattern).CoolingSource(water / water-glycol / dielectric / refrigerant / other); the whole loop shares it.cooling_capacity) stays single-unit kW — the universal standard for IT cooling load, so no unit selector.Design rationale
CablePath), so connections are direct FKs; individual hoses aren't inventoried.CoolingFeedrepresents the whole loop rather than splitting it into a supply feed and a return feed.CoolingIntakedoesn't store its servingCoolingFeed; the feed is resolved from the device's rack. This avoids a denormalized FK that could drift out of sync when a device is moved.CoolingIntake → CoolingOutflowis many-to-one, so there's no M2M requiring athrough; the intake row is already the per-connection record. A dedicated connection model would only be warranted for multi-source intakes (redundancy is modeled as multiple intakes, like dual-PSU) or physical-hose inventory.Devices rather than rack booleans — mirroring how NetBox has nohas_pdu/has_upsflag. Rack-level liquid readiness is still expressed viaRack.cooling_capability.Deferred (non-schema) decisions
u_height=0) devices, reusing the vertical-PDU pattern. A generic mounting-type field, if wanted, is a DCIM-wide enhancement, not cooling-specific.Data model (fields & relationships)
New models list all declared fields; existing models list only the fields added by this feature.
FK →marks a foreign key;_abs_*are internal columns holding the normalized value (L/min, mm) for consistent sorting/filtering.New models
Existing models — added fields only
Relationships (all foreign keys — no new many-to-many)
A device's serving
CoolingFeedis not a stored FK; it is derived from the device's rack (Rack.cooling_feeds).Scope
Full surface area for every new model: choice sets, filtersets, forms (model/bulk-edit/bulk-import/filter/create), tables, REST API (serializers, viewsets, routes), GraphQL (types, filters, queries), search indexes, navigation (new Cooling menu), UI panels/templates, and database migrations.