Introduction to NetBox/Nautobot Modeling
NetBox and its fork Nautobot are open‑source IPAM/DCIM platforms. Core DCIM models include:
- Device – physical or virtual equipment (router, switch, firewall, server).
- Device Type – hardware template (height, power draw, etc.).
- Device Role – functional classification (core, distribution, access, firewall, etc.).
- Device Bay – a slot inside a device that can host another device (e.g., line card, modular blade).
- Device Component – sub‑elements such as interfaces, console ports, power ports, and rear ports.
- Device Relationship – a generic many‑to‑many link between two devices with a user‑defined type (e.g., “MLAG peer”, “stack member”, “virtual chassis member”).
- Tags – free‑form labels for grouping or marking devices.
- Custom Fields – user‑defined key/value pairs attached to any model.
Both platforms expose a REST API, a GraphQL endpoint, and the Python client library pynautobot. Nautobot adds a job framework and app‑extension model for custom validation and UI extensions without altering core code.
Importance of Accurate Network Modeling
An accurate model is the foundation for:
- Automation – configuration generators, compliance checks, and change‑control workflows rely on a single source of truth.
- Incident Response – topology queries must reflect real failure domains; conflating distinct devices can hide single points of failure.
- Capacity Planning – power, cooling, and rack‑unit calculations depend on correct device hierarchy.
- Audit & Security – tags and relationships support policy enforcement (e.g., “all clustered firewalls must have HA‑sync enabled”).
Misrepresenting relationships can lead to automation that applies changes to the wrong device, creates false dependency graphs, or triggers unnecessary rollbacks. Therefore, any modeling approach must preserve the real failure domain of each physical unit while still providing a convenient abstraction for operational workflows.
MLAG Peers Representation
Virtual Devices (Discouraged)
A virtual device has no physical counterpart (no device type, no serial number). Using it to represent an MLAG pair:
- Failure‑domain collapse – automation may treat the pair as a single entity and ignore per‑member health checks.
- Limited attribute inheritance – interfaces, power ports, and console ports must be duplicated manually.
Virtual devices are only appropriate for service‑level objects that are never used for device‑level automation.
Recommended: Device Relationship
Keep each switch as a distinct Device record and create a Device Relationship of type mlag-peer. This preserves individual failure domains while providing a queryable link.
Key properties
- Bidirectional – query either device to get its peer.
- Typed – relationship type can hold custom fields (e.g.,
mlag-domain-id,peer-link-interfaces). - No data duplication – interfaces, MAC addresses, and serial numbers stay on the physical device records.
- Plugin‑compatible – many NetBox/Nautobot plugins (e.g.,
netbox-mlag) expect this pattern.
API Example
import pynautobot
nb = pynautobot.api(
url="https://netbox.example.com",
token="my_api_token"
)
device_a = nb.dcim.devices.get(name="leaf01")
device_b = nb.dcim.devices.get(name="leaf02")
mlag_rel_type = nb.extras.relationship_types.get(name="mlag-peer")
nb.dcim.device_relationship.create(
relationship_type=mlag_rel_type.id,
source_device=device_a.id,
destination_device=device_b.id,
custom_fields={"mlag_domain_id": 101}
)
Assumptions & Limitations
- The relationship type
mlag-peermust exist beforehand (created via UI or migration). - Custom fields on the relationship are optional but useful for storing domain‑specific data.
- Each device remains independently queryable for health checks, interface statistics, and replacement workflows.
Stacked Systems Representation
Why Device Bays Are Misleading
A Device Bay models a physical slot (e.g., a line card). True stacking (Cisco StackWise, Juniper Virtual Chassis) connects separate physical devices via stack cables or a backplane, not via a bay. Using bays implies a parent‑child containment hierarchy that does not exist electrically and can skew power/cooling calculations.
Faithful Approach: Devices + Relationships (+ Optional Components)
- Create a Device record for each physical switch in the stack.
- Identify stack‑interconnect interfaces (e.g.,
Te1/0/1,Te1/0/2on a Cisco 3850). - Optionally create a custom component type (e.g., “Stack Port”) and attach it to those interfaces for clearer labeling.
- Create a
stack-memberDevice Relationship between every pair of devices (or hub‑spoke from a designated master to all members).
API Example
import pynautobot
nb = pynautobot.api(
url="https://netbox.example.com",
token="my_api_token"
)
switch_a = nb.dcim.devices.get(name="switch01")
switch_b = nb.dcim.devices.get(name="switch02")
stack_rel_type = nb.extras.relationship_types.get(name="stack-member")
nb.dcim.device_relationship.create(
relationship_type=stack_rel_type.id,
source_device=switch_a.id,
destination_device=switch_b.id,
custom_fields={"stack_id": 1}
)
Assumptions & Limitations
- The CLI command shown in the draft is illustrative; core NetBox/Nautobot does not ship a
nautobot-cli. Use the REST API orpynautobotdirectly, or wrap them in a custom management command if desired. - Modeling each stack member as a separate device preserves individual failure domains (e.g., a power supply failure on one unit does not affect another).
- Stack bandwidth or protocol version must be captured in custom fields or documentation if needed for automation.
Clustered Firewalls Representation
Clustering (Palo Alto HA pair, Cisco ASA cluster, Fortinet FGCP) is analogous to MLAG: multiple devices act as a single logical security gateway while remaining distinct hardware.
Modeling Pattern
- Keep each firewall as its own Device record.
- Use a Device Relationship type such as
cluster-memberorha-pair. - Add custom fields on the relationship for cluster‑specific data (virtual IP, HA sync interface, sync status).
- Optionally apply a Tag (e.g.,
clustered-firewall) for quick filtering or bulk operations; tags do not replace relationships.
API Example
import pynautobot
nb = pynautobot.api(
url="https://netbox.example.com",
token="my_api_token"
)
fw_a = nb.dcim.devices.get(name="fw-01")
fw_b = nb.dcim.devices.get(name="fw-02")
cluster_rel_type = nb.extras.relationship_types.get(name="cluster-member")
nb.dcim.device_relationship.create(
relationship_type=cluster_rel_type.id,
source_device=fw_a.id,
destination_device=fw_b.id,
custom_fields={
"virtual_ip": "10.0.0.1",
"ha_sync_interface": "eth1",
"ha_mode": "active-passive"
}
)
# Optional tagging for bulk ops
tag = nb.extras.tags.get(name="clustered-firewall")
if tag:
fw_a.tags.add([tag.id])
fw_b.tags.add([tag.id])
fw_a.save()
fw_b.save()
Assumptions & Limitations
- The relationship type
cluster-membermust be pre‑defined. - Custom fields on the relationship store cluster‑specific attributes without polluting the device model.
- Tagging is additive; automation that relies solely on the tag must still query the underlying devices for health checks.
Virtual Chassis Representation
A Virtual Chassis (VC) (Juniper EX/QFX, Aruba VSF) binds multiple switches into a single logical control plane while retaining individual line cards and power supplies.
Modeling Options
- Master/Member Relationship – designate one device as the VC master and create a
vc-memberrelationship from the master to each member. - Device Roles – assign roles such as
vc-masterandvc-memberto differentiate function. - Optional Virtual Device – some teams create a virtual device to represent the VC as a whole for service‑level mapping; label it clearly and avoid using it for device‑level automation.
Roles + Relationships Workflow
- Roles indicate function (master vs. member) and enable UI/API filtering (
?role=vc-member). - Relationships capture the topology (which members belong to which master).
API Example (Master‑Centred)
import pynautobot
nb = pynautobot.api(
url="https://netbox.example.com",
token="my_api_token"
)
master = nb.dcim.devices.get(name="vc-master01")
member = nb.dcim.devices.get(name="vc-member02")
vc_rel_type = nb.extras.relationship_types.get(name="vc-member")
nb.dcim.device_relationship.create(
relationship_type=vc_rel_type.id,
source_device=master.id,
destination_device=member.id,
custom_fields={"vc_priority": 100, "vc_id": 1}
)
# Assign roles (optional but useful for filtering)
master_role = nb.extras.device_roles.get(name="vc-master")
member_role = nb.extras.device_roles.get(name="vc-member")
master.role = master_role
member.role = member_role
master.save()
member.save()
Assumptions & Limitations
- The VC master is not necessarily a single point of data‑plane traffic; control‑plane separation may still exist. Verify the specific VC implementation’s failover behavior before assuming master loss disconnects all members.
- Custom fields on the relationship can store VC‑specific parameters (e.g.,
vc_id,member_id,preempt). - If the VC uses dedicated control‑plane links (VCP ports), model those as interfaces on each device and optionally tag them with
vc-portfor clarity.
Troubleshooting Common Issues
Symptom: Automation Applies Changes to the Wrong Device
- Check: Query the relationship type and direction to verify links.
rels = nb.dcim.device_relationship.filter(
relationship_type__name="mlag-peer",
source_device__name="leaf01"
)
for r in rels:
print(f"{r.source_device.name} -> {r.destination_device.name}")
- Resolution: Ensure the relationship type is correct and that source/destination assignments match the intended semantics. For non‑directional relationships, treat either end as equivalent but remain consistent in automation logic.
Symptom: Missing or Duplicate Relationships
- Check: List all relationships of a given type for a device.
all_rels = nb.dcim.device_relationship.filter(
relationship_type__name="stack-member",
destination_device__name="switch02"
)
- Resolution: Create missing relationships or delete duplicates via the UI or API. Use a unique constraint on
(relationship_type, source_device, destination_device)if your environment requires it.
Symptom: Tags Not Reflecting Expected Groupings
- Check: Verify tag assignments on devices.
tagged = nb.dcim.devices.filter(tag="clustered-firewall")
- Resolution: Add or remove tags as needed; remember that tags are for grouping only and do not encode pairwise relationships.
By adhering to the patterns above—distinct Device records linked via typed Relationships, complemented by Roles and Tags where appropriate—you preserve real failure domains while gaining the abstractions needed for automation, incident response, and capacity planning.