diff --git a/src/infragraph/blueprints/devices/dell/xe9680.py b/src/infragraph/blueprints/devices/dell/xe9680.py new file mode 100644 index 0000000..af46c7d --- /dev/null +++ b/src/infragraph/blueprints/devices/dell/xe9680.py @@ -0,0 +1,248 @@ +from infragraph.infragraph import * +from typing import Optional, Union, Literal + +NicSpec = Union[str, Device] +StorageType = Literal["e3.s", "u.2nvme", "u.2sas/sata"] +XpuType = Literal["h100", "h200", "h20", "a100", "mi300x", "gaudi3"] + + +class Dellxe9680(Device): + def __init__( + self, + nic_device: Optional[NicSpec] = None, + storage_type: StorageType = "u.2nvme", + xpu_type: XpuType = "h200", + ): + super(Device, self).__init__() + self.nic_device = nic_device + self.name = "xe9680" + self.description = "Dell PowerEdge XE9680" + + XPU_CATALOG = { + "h100": { + "description": "NVIDIA HGX H100 80GB 700W SXM5", + "fabric": "nvlink_4", + "count": 8, + "nvswitch_count": 4, + }, + "h200": { + "description": "NVIDIA HGX H200 141GB 700W SXM5", + "fabric": "nvlink_4", + "count": 8, + "nvswitch_count": 4, + }, + "h20": { + "description": "NVIDIA HGX H20 96GB 500W SXM5", + "fabric": "nvlink_4", + "count": 8, + "nvswitch_count": 4, + }, + "a100": { + "description": "NVIDIA HGX A100 80GB 500W SXM4", + "fabric": "nvlink_3", + "count": 8, + "nvswitch_count": 6, + }, + "mi300x": { + "description": "AMD INSTINCT MI300X 192GB 750W OAM", + "fabric": "infinity_fabric", + "count": 8, + "nvswitch_count": 0, + }, + "gaudi3": { + "description": "Intel Gaudi3 128GB 900W OAM", + "fabric": "osfp_link", + "count": 8, + "nvswitch_count": 0, + }, + } + + STORAGE_CATALOG = { + "e3.s": { + "description": "Front bays: E3.S EDSFF (PCIe Gen5 x4 via PSB)", + "count": 16, + "drives_per_sw": 4, + }, + "u.2nvme": { + "description": "Front bays: U.2 NVMe (via PSB)", + "count": 8, + "drives_per_sw": 2, + }, + "u.2sas/sata": { + "description": "U.2 SAS/SATA (via fPERC)", + "count": 8, + "drives_per_sw": 0, + }, + } + + xpu_cfg = XPU_CATALOG[xpu_type] + storage_cfg = STORAGE_CATALOG[storage_type] + + cpu = self.components.add( + name="cpu", + description="4th or 5th gen Intel Xeon Scalable", + count=2, + ) + cpu.choice = Component.CPU + + xpu = self.components.add( + name="xpu", + description=xpu_cfg["description"], + count=xpu_cfg["count"], + ) + xpu.choice = Component.XPU + + nvswitch_count = xpu_cfg["nvswitch_count"] + nvsw = None + if nvswitch_count > 0: + nvsw = self.components.add( + name="nvsw", + description="NVIDIA NVSwitch", + count=nvswitch_count, + ) + nvsw.choice = Component.SWITCH + + pcisw = self.components.add( + name="pciesw", + description="PCIe switches SW1-SW4", + count=4, + ) + pcisw.choice = Component.SWITCH + + pciesl = self.components.add( + name="pciesl", + description="PCIe Gen5 x16 FHHL slots (8 general + 2 smart NIC/DPU dedicated)", + count=10, + ) + pciesl.choice = Component.CUSTOM + pciesl.custom.type = "pcie_slot" + + memory = self.components.add( + name="memory", + description="DDR5 RDIMM (32 slots, up to 4TB, up to 5600 MT/s)", + count=32, + ) + memory.choice = Component.MEMORY + + storage = self.components.add( + name="storage", + description=storage_cfg["description"], + count=storage_cfg["count"], + ) + storage.choice = Component.CUSTOM + + fperc = None + if storage_type == "u.2sas/sata": + fperc = self.components.add( + name="fperc", + description="fPERC H965i SAS/SATA RAID controller", + count=1, + ) + fperc.choice = Component.CUSTOM + + lom = self.components.add( + name="lom", + description="LOM 1GbE x2", + count=2, + ) + lom.choice = Component.NIC + + if self.nic_device is not None: + ocp = self.components.add( + name="ocp", + description="OCP 3.0 NIC", + count=1, + ) + ocp.choice = Component.NIC + + #Links + upi = self.links.add(name="upi", description="Intel UPI inter-CPU fabric") + xpu_fabric_name = xpu_cfg["fabric"] + xpu_link = self.links.add(name=xpu_fabric_name, description=f"{xpu_fabric_name} XPU fabric") + pci = self.links.add(name="pcie_gen5", description="PCI Express Gen 5.0 x16") + ddr5 = self.links.add(name="ddr5", description="DDR5 up to 5600 MT/s") + + #CPU + edge = self.edges.add(DeviceEdge.MANY2MANY, link=upi.name) + edge.ep1.component = f"{cpu.name}" + edge.ep2.component = f"{cpu.name}" + + #PCIe switches to CPUs + for cpu_index in range(cpu.count): + e = self.edges.add(DeviceEdge.ONE2ONE, link=pci.name) + e.ep1.component = f"{pcisw.name}[{2 * cpu_index}]" + e.ep2.component = f"{cpu.name}[{cpu_index}]" + + e = self.edges.add(DeviceEdge.ONE2ONE, link=pci.name) + e.ep1.component = f"{pcisw.name}[{2 * cpu_index + 1}]" + e.ep2.component = f"{cpu.name}[{cpu_index}]" + + #PCIe switches to GPUs + pciesw_to_xpu = {0: [0, 1], + 1: [2, 3], + 2: [4, 5], + 3: [6, 7]} + for sw, gpus in pciesw_to_xpu.items(): + e = self.edges.add(DeviceEdge.MANY2MANY, link=pci.name) + e.ep1.component = f"{pcisw.name}[{sw}]" + e.ep2.component = f"{xpu.name}[{gpus[0]}:{gpus[1] + 1}]" + + + #PCIe switches to PCIe slots + pciesw_to_pciesl = {0: [0, 1, 2], + 1: [3, 4], + 2: [5, 6], + 3: [7, 8, 9]} + for sw, sl in pciesw_to_pciesl.items(): + e = self.edges.add(DeviceEdge.MANY2MANY, link=pci.name) + e.ep1.component = f"{pcisw.name}[{sw}]" + e.ep2.component = f"{pciesl.name}[{sl[0]}:{sl[-1] + 1}]" + + #Storage + if storage_type in ("e3.s", "u.2nvme"): + drives_per_sw = storage_cfg["drives_per_sw"] + for sw in range(pcisw.count): + e = self.edges.add(DeviceEdge.MANY2MANY, link=pci.name) + e.ep1.component = f"{pcisw.name}[{sw}]" + e.ep2.component = f"{storage.name}[{sw * drives_per_sw}:{sw * drives_per_sw + drives_per_sw}]" + elif storage_type == "u.2sas/sata": + for cpu_index in range(cpu.count): + e = self.edges.add(DeviceEdge.ONE2ONE, link=pci.name) + e.ep1.component = f"{cpu.name}[{cpu_index}]" + e.ep2.component = f"{fperc.name}[0]" + e = self.edges.add(DeviceEdge.MANY2MANY, link=pci.name) + e.ep1.component = f"{fperc.name}[0]" + e.ep2.component = f"{storage.name}[0:{storage.count}]" + + #XPU fabric + if xpu_fabric_name in ("nvlink_3", "nvlink_4"): + e = self.edges.add(DeviceEdge.MANY2MANY, link=xpu_link.name) + e.ep1.component = f"{xpu.name}[0:{xpu.count}]" + e.ep2.component = f"{nvsw.name}[0:{nvswitch_count}]" + elif xpu_fabric_name in ("infinity_fabric", "osfp_link"): + e = self.edges.add(DeviceEdge.MANY2MANY, link=xpu_link.name) + e.ep1.component = f"{xpu.name}[0:{xpu.count}]" + e.ep2.component = f"{xpu.name}[0:{xpu.count}]" + + #Memory + dimms_per_cpu = memory.count // cpu.count + for cpu_index in range(cpu.count): + start = cpu_index * dimms_per_cpu + e = self.edges.add(DeviceEdge.MANY2MANY, link=ddr5.name) + e.ep1.component = f"{cpu.name}[{cpu_index}]" + e.ep2.component = f"{memory.name}[{start}:{start + dimms_per_cpu}]" + + #NIC + e = self.edges.add(DeviceEdge.MANY2MANY, link=pci.name) + e.ep1.component = f"{cpu.name}[0]" + e.ep2.component = f"{lom.name}[0:2]" + + if self.nic_device is not None: + e = self.edges.add(DeviceEdge.ONE2ONE, link=pci.name) + e.ep1.component = f"{cpu.name}[0]" + e.ep2.component = f"{ocp.name}[0]" + + +if __name__ == "__main__": + device = Dellxe9680(xpu_type="h200", storage_type="u.2nvme") + print(device.serialize(encoding=Device.YAML)) \ No newline at end of file diff --git a/src/infragraph/blueprints/devices/dell/xe9680L.py b/src/infragraph/blueprints/devices/dell/xe9680L.py new file mode 100644 index 0000000..5945ed6 --- /dev/null +++ b/src/infragraph/blueprints/devices/dell/xe9680L.py @@ -0,0 +1,174 @@ +from infragraph.infragraph import * +from typing import Optional, Union, Literal + +NicSpec = Union[str, Device] +XpuType = Literal["h200", "b200"] + + +class Dellxe9680L(Device): + def __init__( + self, + nic_device: Optional[NicSpec] = None, + xpu_type: XpuType = "h200", + ): + super(Device, self).__init__() + self.nic_device = nic_device + self.name = "xe9680L" + self.description = "Dell PowerEdge XE9680L" + + XPU_CATALOG = { + "h200": { + "description": "NVIDIA HGX H200 141GB 700W SXM5", + "fabric": "nvlink_4", + "count": 8, + "nvswitch_count": 4, + }, + "b200": { + "description": "NVIDIA HGX B200 180GB 1000W SXM6", + "fabric": "nvlink_4", + "count": 8, + "nvswitch_count": 4, + }, + } + + xpu_cfg = XPU_CATALOG[xpu_type] + + cpu = self.components.add( + name="cpu", + description="5th gen Intel Xeon Scalable", + count=2, + ) + cpu.choice = Component.CPU + + xpu = self.components.add( + name="xpu", + description=xpu_cfg["description"], + count=xpu_cfg["count"], + ) + xpu.choice = Component.XPU + + nvsw = self.components.add( + name="nvsw", + description="NVIDIA NVSwitch", + count=xpu_cfg["nvswitch_count"], + ) + nvsw.choice = Component.SWITCH + + pcisw = self.components.add( + name="pciesw", + description="PCIe switches SW1-SW4", + count=4, + ) + pcisw.choice = Component.SWITCH + + pciesl = self.components.add( + name="pciesl", + description="PCIe Gen5 x16 FHHL slots (10 general + 2 NIC/DPU dedicated)", + count=12, + ) + pciesl.choice = Component.CUSTOM + pciesl.custom.type = "pcie_slot" + + memory = self.components.add( + name="memory", + description="DDR5 RDIMM (32 slots, up to 4TB, up to 5600 MT/s)", + count=32, + ) + memory.choice = Component.MEMORY + + storage = self.components.add( + name="storage", + description="Front bays: 8x U.2 NVMe direct from PSB (PCIe Gen5)", + count=8, + ) + storage.choice = Component.CUSTOM + + lom = self.components.add( + name="lom", + description="LOM 1GbE x2", + count=2, + ) + lom.choice = Component.NIC + + if self.nic_device is not None: + ocp = self.components.add( + name="ocp", + description="OCP 3.0 NIC", + count=1, + ) + ocp.choice = Component.NIC + + #Links + upi = self.links.add(name="upi", description="Intel UPI inter-CPU fabric") + nvlink = self.links.add(name="nvlink_4", description="NVLink 4.0 XPU fabric") + pci = self.links.add(name="pcie_gen5", description="PCI Express Gen 5.0 x16") + ddr5 = self.links.add(name="ddr5", description="DDR5 up to 5600 MT/s") + + #CPU + edge = self.edges.add(DeviceEdge.MANY2MANY, link=upi.name) + edge.ep1.component = f"{cpu.name}" + edge.ep2.component = f"{cpu.name}" + + #PCIe switches to CPUs + for cpu_index in range(cpu.count): + e = self.edges.add(DeviceEdge.ONE2ONE, link=pci.name) + e.ep1.component = f"{pcisw.name}[{2 * cpu_index}]" + e.ep2.component = f"{cpu.name}[{cpu_index}]" + + e = self.edges.add(DeviceEdge.ONE2ONE, link=pci.name) + e.ep1.component = f"{pcisw.name}[{2 * cpu_index + 1}]" + e.ep2.component = f"{cpu.name}[{cpu_index}]" + + #PCIe switches to GPUs + pciesw_to_xpu = {0: [0, 1], + 1: [2, 3], + 2: [4, 5], + 3: [6, 7]} + for sw, gpus in pciesw_to_xpu.items(): + e = self.edges.add(DeviceEdge.MANY2MANY, link=pci.name) + e.ep1.component = f"{pcisw.name}[{sw}]" + e.ep2.component = f"{xpu.name}[{gpus[0]}:{gpus[1] + 1}]" + + #PCIe switches to PCIe slots + pciesw_to_pciesl = {0: [0, 1, 2], + 1: [3, 4, 5], + 2: [6, 7, 8], + 3: [9, 10, 11]} + for sw, sl in pciesw_to_pciesl.items(): + e = self.edges.add(DeviceEdge.MANY2MANY, link=pci.name) + e.ep1.component = f"{pcisw.name}[{sw}]" + e.ep2.component = f"{pciesl.name}[{sl[0]}:{sl[-1] + 1}]" + + #PCIe switches to storage + for sw in range(pcisw.count): + e = self.edges.add(DeviceEdge.MANY2MANY, link=pci.name) + e.ep1.component = f"{pcisw.name}[{sw}]" + e.ep2.component = f"{storage.name}[{sw * 2}:{sw * 2 + 2}]" + + #GPU + e = self.edges.add(DeviceEdge.MANY2MANY, link=nvlink.name) + e.ep1.component = f"{xpu.name}[0:{xpu.count}]" + e.ep2.component = f"{nvsw.name}[0:{nvsw.count}]" + + #Memory + dimms_per_cpu = memory.count // cpu.count + for cpu_index in range(cpu.count): + start = cpu_index * dimms_per_cpu + e = self.edges.add(DeviceEdge.MANY2MANY, link=ddr5.name) + e.ep1.component = f"{cpu.name}[{cpu_index}]" + e.ep2.component = f"{memory.name}[{start}:{start + dimms_per_cpu}]" + + #NIC + e = self.edges.add(DeviceEdge.MANY2MANY, link=pci.name) + e.ep1.component = f"{cpu.name}[0]" + e.ep2.component = f"{lom.name}[0:2]" + + if self.nic_device is not None: + e = self.edges.add(DeviceEdge.ONE2ONE, link=pci.name) + e.ep1.component = f"{cpu.name}[0]" + e.ep2.component = f"{ocp.name}[0]" + + +if __name__ == "__main__": + device = Dellxe9680L(xpu_type="b200") + print(device.serialize(encoding=Device.YAML)) \ No newline at end of file diff --git a/src/infragraph/blueprints/devices/dell/xe9685L.py b/src/infragraph/blueprints/devices/dell/xe9685L.py new file mode 100644 index 0000000..f2c5535 --- /dev/null +++ b/src/infragraph/blueprints/devices/dell/xe9685L.py @@ -0,0 +1,157 @@ +from infragraph.infragraph import * +from typing import Optional, Union + +NicSpec = Union[str, Device] + +class Dellxe9685L(Device): + def __init__(self, nic_device: Optional[NicSpec] = None): + super(Device, self).__init__() + self.nic_device = nic_device + self.name = "xe9685L" + self.description = "Dell PowerEdge device 9685L" + + cpu = self.components.add( + name="cpu", + description="5th Generation AMD EPYC 9005 Series processors", + count=2, + ) + cpu.choice = Component.CPU + + xpu = self.components.add( + name="xpu", + description="NVIDIA HGX B200 180GB 1000W SXM6", + count=8, + ) + xpu.choice = Component.XPU + + nvswitch = self.components.add( + name="nvsw", + description="NV Link switches", + count=4, + ) + nvswitch.choice = Component.SWITCH + + pcisw = self.components.add( + name="pciesw", + description="PCIe switches SW1-SW4", + count=4, + ) + pcisw.choice = Component.SWITCH + + pciesl = self.components.add( + name="pciesl", + description="PCIe Gen5 x16 FHHL slots (10 general + 2 NIC/DPU dedicated)", + count=12, + ) + pciesl.choice = Component.CUSTOM + pciesl.custom.type = "pcie_slot" + + memory = self.components.add( + name="memory", + description="DDR5 RDIMM (24 slots, up to 3TB, up to 6400 MT/s)", + count=24, + ) + memory.choice = Component.MEMORY + + storage = self.components.add( + name="storage", + description="Front bays: 8x U.2 NVMe direct from PSB (PCIe Gen5)", + count=8, + ) + storage.choice = Component.CUSTOM + + nic = self.components.add( + name="lom", + description="LOM 1GbE", + count=2, + ) + nic.choice = Component.NIC + + if self.nic_device is not None: + ocp = self.components.add( + name="ocp", + description="OCP 3.0 NIC", + count=1, + ) + ocp.choice = Component.NIC + + gmi = self.links.add(name="gmi", description="Global memory link 16GT/s") + nvlink = self.links.add(name="nvlink_4", description="NVLink 4.0 100GT/s") + pci = self.links.add(name="pcie_gen5", description="PCI Express Gen 5.0 32GT/s") + ddr5 = self.links.add(name="ddr5", description="DDR5 6400MT/s") + + #CPU + edge = self.edges.add(DeviceEdge.MANY2MANY, link=gmi.name) + edge.ep1.component = f"{cpu.name}" + edge.ep2.component = f"{cpu.name}" + + #pcie connections + pciesw_to_xpu_mapping = { + 0: [0, 1], + 1: [2, 3], + 2: [4, 5], + 3: [6, 7], + } + + pciesw_to_pciesl_mapping = { + 0: [0, 1, 2], + 1: [3, 4, 5], + 2: [6, 7, 8], + 3: [9, 10, 11], + } + + #PCIe switches to GPUs + for sw, gpus in pciesw_to_xpu_mapping.items(): + e = self.edges.add(DeviceEdge.MANY2MANY, link=pci.name) + e.ep1.component = f"{pcisw.name}[{sw}]" + e.ep2.component = f"{xpu.name}[{gpus[0]}:{gpus[1] + 1}]" + + #PCIe switches to PCIe slots + for sw, sl in pciesw_to_pciesl_mapping.items(): + e = self.edges.add(DeviceEdge.MANY2MANY, link=pci.name) + e.ep1.component = f"{pcisw.name}[{sw}]" + e.ep2.component = f"{pciesl.name}[{sl[0]}:{sl[-1] + 1}]" + + #PCIe switches to CPUs + for cpu_index in range(cpu.count): + e = self.edges.add(DeviceEdge.ONE2ONE, link=pci.name) + e.ep1.component = f"{pcisw.name}[{2 * cpu_index}]" + e.ep2.component = f"{cpu.name}[{cpu_index}]" + + e = self.edges.add(DeviceEdge.ONE2ONE, link=pci.name) + e.ep1.component = f"{pcisw.name}[{2 * cpu_index + 1}]" + e.ep2.component = f"{cpu.name}[{cpu_index}]" + + #PCIe switches to storage + for sw in range(pcisw.count): + e = self.edges.add(DeviceEdge.MANY2MANY, link=pci.name) + e.ep1.component = f"{pcisw.name}[{sw}]" + e.ep2.component = f"{storage.name}[{sw * 2}:{sw * 2 + 2}]" + + #GPUs + e = self.edges.add(DeviceEdge.MANY2MANY, link=nvlink.name) + e.ep1.component = f"{xpu.name}[0:{xpu.count}]" + e.ep2.component = f"{nvswitch.name}[0:{nvswitch.count}]" + + #Memory + dimms_per_cpu = memory.count // cpu.count + for cpu_index in range(cpu.count): + start = cpu_index * dimms_per_cpu + e = self.edges.add(DeviceEdge.MANY2MANY, link=ddr5.name) + e.ep1.component = f"{cpu.name}[{cpu_index}]" + e.ep2.component = f"{memory.name}[{start}:{start + dimms_per_cpu}]" + + #NIC + e = self.edges.add(DeviceEdge.MANY2MANY, link=pci.name) + e.ep1.component = f"{cpu.name}[0]" + e.ep2.component = f"{nic.name}[0:2]" + + if self.nic_device is not None: + e = self.edges.add(DeviceEdge.ONE2ONE, link=pci.name) + e.ep1.component = f"{cpu.name}[0]" + e.ep2.component = f"{ocp.name}[0]" + + +if __name__ == "__main__": + device = Dellxe9685L() + print(device.serialize(encoding=Device.YAML)) \ No newline at end of file diff --git a/src/tests/test_blueprints/test_xe9680.py b/src/tests/test_blueprints/test_xe9680.py new file mode 100644 index 0000000..1007591 --- /dev/null +++ b/src/tests/test_blueprints/test_xe9680.py @@ -0,0 +1,45 @@ +import pytest +import networkx +from infragraph.infragraph import Api +from infragraph.infragraph_service import InfraGraphService +from infragraph.blueprints.devices.dell.xe9680 import Dellxe9680 + + +@pytest.mark.asyncio +@pytest.mark.parametrize("count", [1, 2]) +@pytest.mark.parametrize( + "xpu_type, storage_type, nic_device", + [ + ("h200", "u.2nvme", None), + ("h100", "e3.s", None), + ("a100", "u.2nvme", None), + ("h20", "u.2sas/sata", None), + ("mi300x", "u.2nvme", None), + ("gaudi3", "e3.s", None), + ("h200", "u.2nvme", "ocp"), + ], +) +async def test_dellxe9680(count, xpu_type, storage_type, nic_device): + """From a Dellxe9680 device, generate a graph and validate the graph. + + - with a count > 1 there should be no connectivity between device instances + """ + device = Dellxe9680( + xpu_type=xpu_type, + storage_type=storage_type, + nic_device=nic_device, + ) + device.validate() + infrastructure = Api().infrastructure() + infrastructure.devices.append(device) + infrastructure.instances.add(name=device.name, device=device.name, count=count) + service = InfraGraphService() + service.set_graph(infrastructure) + + g = service.get_networkx_graph() + print(f"\ndevice {device.name} xpu={xpu_type} storage={storage_type} nic={nic_device} count={count}") + print(networkx.write_network_text(g, vertical_chains=True)) + + +if __name__ == "__main__": + pytest.main(["-s", __file__]) \ No newline at end of file diff --git a/src/tests/test_blueprints/test_xe9680L.py b/src/tests/test_blueprints/test_xe9680L.py new file mode 100644 index 0000000..018dec5 --- /dev/null +++ b/src/tests/test_blueprints/test_xe9680L.py @@ -0,0 +1,41 @@ +import pytest +import networkx +from infragraph.infragraph import Api +from infragraph.infragraph_service import InfraGraphService +from infragraph.blueprints.devices.dell.xe9680L import Dellxe9680L + + +@pytest.mark.asyncio +@pytest.mark.parametrize("count", [1, 2]) +@pytest.mark.parametrize( + "xpu_type, nic_device", + [ + ("h200", None), + ("h200", "ocp"), + ("b200", None), + ("b200", "ocp"), + ], +) +async def test_dellxe9680L(count, xpu_type, nic_device): + """From a Dellxe9680L device, generate a graph and validate the graph. + + - with a count > 1 there should be no connectivity between device instances + """ + device = Dellxe9680L( + xpu_type=xpu_type, + nic_device=nic_device, + ) + device.validate() + infrastructure = Api().infrastructure() + infrastructure.devices.append(device) + infrastructure.instances.add(name=device.name, device=device.name, count=count) + service = InfraGraphService() + service.set_graph(infrastructure) + + g = service.get_networkx_graph() + print(f"\ndevice {device.name} xpu={xpu_type} nic={nic_device} count={count}") + print(networkx.write_network_text(g, vertical_chains=True)) + + +if __name__ == "__main__": + pytest.main(["-s", __file__]) \ No newline at end of file diff --git a/src/tests/test_blueprints/test_xe9685L.py b/src/tests/test_blueprints/test_xe9685L.py new file mode 100644 index 0000000..30b3bb7 --- /dev/null +++ b/src/tests/test_blueprints/test_xe9685L.py @@ -0,0 +1,38 @@ +import pytest +import networkx +from infragraph.infragraph import Api +from infragraph.infragraph_service import InfraGraphService +from infragraph.blueprints.devices.dell.xe9685L import Dellxe9685L + + +@pytest.mark.asyncio +@pytest.mark.parametrize("count", [1, 2]) +@pytest.mark.parametrize( + "nic_device", + [ + None, + "ocp", + ], +) +async def test_dellxe9680L(count, nic_device): + """From a Dellxe9685L device, generate a graph and validate the graph. + + - with a count > 1 there should be no connectivity between device instances + """ + device = Dellxe9685L( + nic_device=nic_device, + ) + device.validate() + infrastructure = Api().infrastructure() + infrastructure.devices.append(device) + infrastructure.instances.add(name=device.name, device=device.name, count=count) + service = InfraGraphService() + service.set_graph(infrastructure) + + g = service.get_networkx_graph() + print(f"\ndevice {device.name} nic={nic_device} count={count}") + print(networkx.write_network_text(g, vertical_chains=True)) + + +if __name__ == "__main__": + pytest.main(["-s", __file__]) \ No newline at end of file