Generics & inheritance
A Generic in Infrahub is a reusable base that shares attributes and relationships across multiple node types. They work similarly to abstract base classes or interfaces in object-oriented programming — you define common structure once, and node types that inherit_from a generic receive that structure automatically.
When to use a generic
Use a Node when you need to represent a concrete object in your infrastructure model with specific attributes and relationships.
Use a Generic when you want to share common attributes or relationships across multiple node types. This helps to avoid redundancy and ensures consistency across your schema. Generics can also be used to connect multiple types of Nodes to the same relationship.
Define a generic
You define a generic in the generics section of a schema file. Like a node, it has a name, a namespace, and attributes and relationships. A generic has no inherit_from property: only nodes inherit from generics. See the generic schema reference for every property.
This example defines two generics. DcimPhysicalDevice defines what every physical device has: a serial_number and a location. LocationPhysical defines what every physical location has: a name and the list of devices installed there.
generics:
- name: PhysicalDevice
namespace: Dcim
description: Attributes and relationships of every physical device.
icon: mdi:server
attributes:
- name: serial_number
kind: Text
optional: true
relationships:
- name: location
peer: LocationPhysical
kind: Attribute
cardinality: one
optional: false
identifier: physical_device__physical_location
- name: Physical
namespace: Location
description: Attributes and relationships of every physical location, such as a site or a rack.
attributes:
- name: name
kind: Text
unique: true
relationships:
- name: devices
peer: DcimPhysicalDevice
kind: Generic
cardinality: many
identifier: physical_device__physical_location
Inherit from a generic
To make a node inherit from a generic, list the generic's kind in the node's inherit_from property. The node receives every attribute and relationship of the generic.
nodes:
- name: Device
namespace: Dcim
inherit_from:
- DcimPhysicalDevice
# Attributes and relationships specific to DcimDevice
- name: Firewall
namespace: Security
inherit_from:
- DcimPhysicalDevice
# Attributes and relationships specific to SecurityFirewall
- name: Rack
namespace: Location
inherit_from:
- LocationPhysical
# Attributes and relationships specific to LocationRack
DcimDevice and SecurityFirewall both have the serial_number attribute and the location relationship of DcimPhysicalDevice. LocationRack has the name attribute and the devices relationship of LocationPhysical, so a rack can hold both devices and firewalls.
Inherit from several generics
A node can inherit from several generics. It receives the attributes and relationships of each one.
generics:
- name: Asset
namespace: Dcim
icon: mdi:barcode
attributes:
- name: asset_tag
kind: Text
unique: true
nodes:
- name: Device
namespace: Dcim
inherit_from:
- DcimPhysicalDevice
- DcimAsset
DcimDevice has serial_number and location from DcimPhysicalDevice, and asset_tag from DcimAsset.
When two generics define an attribute or a relationship with the same name, the node receives one attribute or relationship under that name, if the two definitions are compatible:
-
Attribute: both definitions must have the same
kind. Infrahub refuses the load otherwise:DcimDevice.asset_tag inherited from DcimAsset must be the same kind ["Number", "Text"]When the kinds are the same, the other properties of the attribute, such as
labeloroptional, come from the generic listed last ininherit_from. Define the attribute the same way on both generics so that the result does not depend on the order ofinherit_from. -
Relationship: both definitions must have the same
peer,kind,identifier,cardinality,optionaland other properties that define the stored links. Only properties such aslabelanddescriptioncan differ. Infrahub refuses the load otherwise:DcimDevice inherits from 'DcimPhysicalDevice' & 'DcimAsset' with different 'peer' on the 'location' relationship
Node-level properties
A node also receives these properties from its generics, when the node does not set them itself:
human_friendly_iddisplay_labeldefault_filteruniqueness_constraintsorder_byiconmenu_placement
When several generics set the same property, the node receives the value of the first generic in inherit_from that sets it. In the example above, both generics set icon, so DcimDevice receives mdi:server from DcimPhysicalDevice.
A node receives these properties when it is first loaded, and keeps them afterwards. If you change one of them on the generic later, Infrahub does not apply the change to a node that already has a value for it: set the new value on each node.
Override an inherited attribute or relationship
A node inherits an attribute or relationship of its generic as long as the node's own definition does not include one with the same name. To give one node a different definition, for example a different label, define the attribute or relationship on the node with the same name. The node then overrides it:
generics:
- name: PhysicalDevice
namespace: Dcim
attributes:
- name: serial_number
kind: Text
optional: true
nodes:
- name: Device
namespace: Dcim
inherit_from: [DcimPhysicalDevice]
attributes:
- name: serial_number # overrides the attribute of DcimPhysicalDevice
kind: Text
optional: true
label: Chassis serial number # used on DcimDevice only
The node's definition replaces the generic's definition completely, so set every property you need on it, not only the one you change. A later change to serial_number on DcimPhysicalDevice does not apply to DcimDevice, because DcimDevice uses its own definition. Other nodes that inherit serial_number still receive the change.
Each time you load the schema, Infrahub checks that the override is compatible with the generic's definition, and refuses the load otherwise:
- An attribute must have the same
kind. ANumberoverride of aTextattribute is refused. - A relationship must have the same
peer.
A node can inherit some attributes and relationships of a generic and override others. In the schema explorer, under Object Management > Schemas, the Inherited row of an attribute or relationship shows true when the node inherits it, and false when the node defines it itself.
Limit how nodes use a generic
By default, any node can inherit from a generic and override any of its attributes and relationships. Two properties restrict this. Use them on a generic that only a known set of nodes should inherit from, or whose attributes must have the same definition on every node.
Prevent nodes from overriding an attribute or relationship
Set allow_override on an attribute or relationship of a generic:
any(default): a node that inherits from the generic can override the attribute or relationship.none: Infrahub refuses to load a node that overrides it.
generics:
- name: PhysicalDevice
namespace: Dcim
attributes:
- name: serial_number
kind: Text
optional: true
allow_override: none
relationships:
- name: location
peer: LocationPhysical
kind: Attribute
cardinality: one
optional: false
identifier: physical_device__physical_location
allow_override: none
nodes:
- name: Device
namespace: Dcim
inherit_from: [DcimPhysicalDevice]
attributes:
- name: serial_number # refused: DcimPhysicalDevice does not allow an override
kind: Text
With allow_override: none, every node that inherits the attribute or relationship uses the generic's definition, so a change to it on the generic applies to all of them.
Restrict which namespaces can inherit from a generic
Set restricted_namespaces on a generic to list the namespaces whose nodes can inherit from it. Infrahub refuses to load a node from any other namespace that lists the generic in inherit_from.
generics:
- name: GenericService
namespace: Customer
restricted_namespaces:
- Customer
attributes:
- name: service_name
kind: Text
unique: true
- name: customer_account
kind: Text
nodes:
- name: SingleSiteService
namespace: Customer # allowed: Customer is in restricted_namespaces
inherit_from:
- CustomerGenericService
attributes:
- name: site_name
kind: Text
- name: CloudService
namespace: Customer # allowed: Customer is in restricted_namespaces
inherit_from:
- CustomerGenericService
- name: HttpService
namespace: Dcim # refused: Dcim is not in restricted_namespaces
inherit_from:
- CustomerGenericService
When restricted_namespaces is not set, nodes from any namespace can inherit from the generic.
Infrahub sets restricted_namespaces on several of its own generics, such as CoreGenericRepository and CoreWebhook, because their behavior depends on Infrahub code written for specific nodes. Only nodes in the Core namespace can inherit from them.
Reserved namespaces
Infrahub refuses a schema that uses one of its reserved namespaces for a node or a generic: Account, Branch, Builtin, Core, Deprecated, Diff, Infrahub, Internal, Lineage, Profile, Schema and Template. Some attribute and relationship names, such as attribute and relationship, are also reserved.
Related concepts
- Nodes & attributes — Node properties and attribute kinds
- Relationships — Relationship kinds, identifiers and relationships to a generic
- Hierarchy — Hierarchical generics for tree structures
- Schema extensions — Adding to existing nodes without redefining them