Skip to content

Feature request: create inventory assets for FRU network modules from network_components SNMP data #931

@JohTechTHD

Description

@JohTechTHD

Summary

glpiinventory collects hardware module data from network switches via SNMP
and stores it in network_components (XML: <COMPONENT> elements). However,
this data is currently not used to create inventory assets — it is discarded
after the parent switch is inventoried.

Data available

For a Cisco C9300 stack, glpiinventory already collects the following
component structure via SNMP:

  <!-- Stack root -->
  <COMPONENT>
    <INDEX>1</INDEX>
    <TYPE>stack</TYPE>
    <CONTAINEDININDEX>0</CONTAINEDININDEX>
    <MODEL>C9300-48P</MODEL>
    <SERIAL>SN_STACK</SERIAL>
  </COMPONENT>

  <!-- Stack member (chassis) -->
  <COMPONENT>
    <INDEX>1000</INDEX>
    <TYPE>chassis</TYPE>
    <CONTAINEDININDEX>1</CONTAINEDININDEX>
    <MODEL>C9300-48P</MODEL>
    <SERIAL>SN_CHASSIS_1</SERIAL>
    <NAME>Switch 1</NAME>
  </COMPONENT>

  <!-- FRU expansion module inside Switch 1 -->
  <COMPONENT>
    <INDEX>1110</INDEX>
    <TYPE>module</TYPE>
    <CONTAINEDININDEX>1061</CONTAINEDININDEX>
    <FRU>1</FRU>
    <MODEL>C9300-NM-8X</MODEL>
    <SERIAL>SN_MODULE_1</SERIAL>
    <DESCRIPTION>8x10G Uplink Module</DESCRIPTION>
    <REVISION>V03</REVISION>
  </COMPONENT>

  <!-- Same module in Switch 2 of the same stack -->
  <COMPONENT>
    <INDEX>2110</INDEX>
    <TYPE>module</TYPE>
    <CONTAINEDININDEX>2061</CONTAINEDININDEX>
    <FRU>1</FRU>
    <MODEL>C9300-NM-8X</MODEL>
    <SERIAL>SN_MODULE_2</SERIAL>
    <DESCRIPTION>8x10G Uplink Module</DESCRIPTION>
    <REVISION>V03</REVISION>
  </COMPONENT>

Fields available per module:

  • TYPE — component type (module, chassis, stack, container, other)
  • FRU1 = Field Replaceable Unit (real hardware asset), 2 = non-replaceable
  • MODEL — hardware model (e.g. C9300-NM-8X, C3850-NM-4-10G)
  • SERIAL — unique serial number
  • REVISION — hardware revision
  • CONTAINEDININDEX — index of the parent component (allows building the hierarchy)

Stack support

A stacked switch is represented as a single NetworkEquipment in GLPI but
physically consists of multiple chassis, each with their own expansion modules.
The CONTAINEDININDEX tree allows resolving which module belongs to which
stack member:

stack (INDEX=1)
 └── chassis Switch 1 (INDEX=1000, CONTAINEDININDEX=1, SERIAL=SN_CHASSIS_1)
      └── module container (INDEX=1061, CONTAINEDININDEX=1000)
           └── C9300-NM-8X (INDEX=1110, CONTAINEDININDEX=1061, SERIAL=SN_MODULE_1)  ← FRU
 └── chassis Switch 2 (INDEX=2000, CONTAINEDININDEX=1, SERIAL=SN_CHASSIS_2)
      └── module container (INDEX=2061, CONTAINEDININDEX=2000)
           └── C9300-NM-8X (INDEX=2110, CONTAINEDININDEX=2061, SERIAL=SN_MODULE_2)  ← FRU

Each module must be linked to the correct stack member (matched via chassis
SERIAL against the NetworkEquipment already in GLPI), not just to the
top-level stack device.

Proposed behavior

For each COMPONENT where FRU=1 AND MODEL is set AND SERIAL is set,
create or update a NetworkEquipment asset in GLPI linked to its parent switch
or stack member. Modules without MODEL or SERIAL (fixed backplane modules,
containers) should be ignored.

Proof of concept

The following logic (currently implemented as a third-party plugin using the
proposed glpiinventory_post_network_inventory hook, see PR #XXX) works
correctly in production on GLPI 11.0.6:

// Build parent index map for hierarchy traversal
$parent_map = [];
foreach ($components as $component) {
    if (property_exists($component, 'index')) {
        $parent_map[$component->index] = $component->contained_index ?? 0;
    }
}

// Walk up the tree to find the chassis index for a given component
$get_chassis_index = function (int $index) use (&$get_chassis_index, $parent_map): int {
    $parent = $parent_map[$index] ?? 0;
    if ($parent === 0 || $parent === 1) {
        return $index;
    }
    return $get_chassis_index($parent);
};

// Collect FRU modules, grouped by chassis
$modules_per_chassis = [];
foreach ($components as $component) {
    if (
        ($component->type   ?? '') === 'module' &&
        ($component->fru    ?? 0)  == 1         &&
        !empty($component->serial)              &&
        !empty($component->model)
    ) {
        $chassis_index = $get_chassis_index($component->index);
        $modules_per_chassis[$chassis_index][] = $component;
    }
}

// Match chassis to the correct NetworkEquipment via serial (stack-aware)
foreach ($stack_members as $member_ne) {
    $chassis_index = /* find chassis index whose SERIAL matches $member_ne->fields['serial'] */;
    foreach ($modules_per_chassis[$chassis_index] ?? [] as $mod) {
        // create or update NetworkEquipment for $mod, link to $member_ne
    }
}

Tested on

glpiinventory 1.6.7 / GLPI 11.0.6 / Cisco Catalyst C9300-48P stack (2 members)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions