Skip to content

Netbox Get Interfaces Task¤

task api name: get_interfaces

Retrieves interface data from NetBox for one or more devices using the REST API. The task can include related IP addresses, inventory items, child interfaces, and LAG member relationships.

Inputs¤

Parameter Required Description
devices No Device names to retrieve interfaces for
interface_list No Exact interface names to retrieve
interface_regex No Regex pattern to match interface names
ip_addresses No Include IP addresses assigned to interfaces
inventory_items No Include inventory items attached to interfaces
instance No NetBox instance name to target
branch No NetBox Branching plugin branch name to read from
dry_run No Return REST filter parameters without querying NetBox
cache No Cache usage mode: True, False, refresh, or force
brief No Return a stripped-down interface payload for smaller context windows

Output¤

Normal mode returns a dictionary keyed by device name and interface name:

{
    "ceos-leaf-1": {
        "Ethernet1": {
            "name": "Ethernet1",
            "type": {"value": "1000base-t", "label": "1000BASE-T"},
            "enabled": True,
            "ip_addresses": [{"address": "192.0.2.1/31"}],
            "inventory_items": [],
            "child_interfaces": [],
            "member_interfaces": [],
            "...": "...",
        },
    },
}

Notes / Gotchas¤

  • interface_list maps to the NFCLI alias interface-list.
  • interface_regex maps to the NFCLI alias interface-regex.
  • brief=True affects only the returned payload. The task still fetches full interface data before reducing it.
  • If no interface data is returned for the selected devices, the task raises an error.

Examples¤

Get all interfaces for a device:

nf#netbox get interfaces devices ceos-leaf-1

Get selected interfaces:

nf#netbox get interfaces devices ceos-leaf-1 interface-list Ethernet1 Ethernet2

Match interfaces by regex and include IP addresses:

nf#netbox get interfaces devices ceos-leaf-1 interface-regex "Ethernet.*" ip-addresses

Include inventory items and refresh cache:

nf#netbox get interfaces devices ceos-leaf-1 inventory-items cache refresh

Preview REST filters:

nf#netbox get interfaces devices ceos-leaf-1 interface-list Ethernet1 dry-run

Context manager:

from norfab.core.nfapi import NorFab

with NorFab(inventory="./inventory.yaml") as nf:
    client = nf.make_client()

    result = client.run_job(
        "netbox",
        "get_interfaces",
        workers="any",
        kwargs={
            "devices": ["ceos-leaf-1"],
            "interface_list": ["Ethernet1", "Ethernet2"],
        },
    )

Direct lifecycle:

from norfab.core.nfapi import NorFab

nf = NorFab(inventory="./inventory.yaml")
try:
    nf.start()
    client = nf.make_client()

    result = client.run_job(
        "netbox",
        "get_interfaces",
        workers="any",
        kwargs={
            "devices": ["ceos-leaf-1"],
            "interface_regex": "Ethernet.*",
            "ip_addresses": True,
            "inventory_items": True,
        },
    )

    branch_result = client.run_job(
        "netbox",
        "get_interfaces",
        workers="any",
        kwargs={
            "devices": ["ceos-leaf-1"],
            "branch": "my-branch",
        },
    )
finally:
    nf.destroy()

NORFAB Netbox Get Interfaces Command Shell Reference¤

NorFab shell supports these command options for Netbox get_interfaces task:

nf# man tree netbox.get.interfaces
root
└── netbox:    Netbox service
    └── get:    Query data from Netbox
        └── interfaces:    Query Netbox device interfaces data
            ├── instance:    Netbox instance name to target
            ├── branch:    Branching plugin branch name to use
            ├── workers:    Filter worker to target, default 'any'
            ├── timeout:    Job timeout
            ├── devices:    Devices to retrieve interface for
            ├── interface-list:    List of interface names to retrieve
            ├── interface-regex:    Regex pattern to match interfaces by name
            ├── ip-addresses:    Retrieves interface IP addresses
            ├── inventory-items:    Retrieves interface inventory items
            ├── dry-run:    Only return query content, do not run it
            ├── cache:    Cache usage mode
            └── brief:    Return stripped-down interface data
nf#

Python API Reference¤

Retrieve device interfaces from Netbox using Pynetbox REST API.

Parameters:

Name Type Description Default
job Job

NorFab Job object containing relevant metadata

required
instance str

Netbox instance name.

None
devices list

List of devices to retrieve interfaces for.

None
interface_list list

List of interface names to retrieve.

None
interface_regex str

Regex pattern to match interfaces by name.

None
ip_addresses bool

If True, retrieves interface IPs. Defaults to False.

False
inventory_items bool

If True, retrieves interface inventory items. Defaults to False.

False
dry_run bool

If True, only return REST filter params, do not run. Defaults to False.

False
cache Union[None, bool, str]

True - use cache if up to date; False - skip cache; "refresh" - fetch and overwrite cache; "force" - use cache without staleness check

None
brief bool

If True, return stripped-down interface data for MCP/LLM context window optimization. Full data is still fetched; brief mode only affects what is returned.

False

Returns:

Name Type Description
dict Result

Dictionary keyed by device name with interface details.

This task performs no filtering of data returned by pynetbox.dcim.interfaces.filter, as a result use netbox REST API explorer to understand resulting data structure, REST API browser available at http://<netbox url>/api/dcim/interfaces/. In addition use nfcli to explore interfaces data:

nf#netbox get interfaces devices fceos4 interface-list eth201 | kv

netbox-worker-1.1.fceos4.eth201.display: eth201
netbox-worker-1.1.fceos4.eth201.device.name: fceos4
...

Can also pipe results through json, yaml, nested or pprint formatters to output results in certain format.

Source code in norfab\workers\netbox_worker\interfaces_tasks.py
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
@Task(
    fastapi={"methods": ["GET"], "schema": NetboxFastApiArgs.model_json_schema()},
    input=GetInterfacesInput,
    output=GetInterfacesResult,
    mcp={
        "annotations": {
            "title": "Get Interfaces",
            "readOnlyHint": True,
            "destructiveHint": False,
            "idempotentHint": True,
            "openWorldHint": True,
        }
    },
)
def get_interfaces(
    self,
    job: Job,
    instance: Union[None, str] = None,
    devices: Union[None, list] = None,
    interface_list: Union[None, list] = None,
    interface_regex: Union[None, str] = None,
    ip_addresses: bool = False,
    inventory_items: bool = False,
    dry_run: bool = False,
    cache: Union[None, bool, str] = None,
    branch: Union[None, str] = None,
    brief: bool = False,
) -> Result:
    """
    Retrieve device interfaces from Netbox using Pynetbox REST API.

    Args:
        job: NorFab Job object containing relevant metadata
        instance (str, optional): Netbox instance name.
        devices (list, optional): List of devices to retrieve interfaces for.
        interface_list (list, optional): List of interface names to retrieve.
        interface_regex (str, optional): Regex pattern to match interfaces by name.
        ip_addresses (bool, optional): If True, retrieves interface IPs. Defaults to False.
        inventory_items (bool, optional): If True, retrieves interface inventory items. Defaults to False.
        dry_run (bool, optional): If True, only return REST filter params, do not run. Defaults to False.
        cache: ``True`` - use cache if up to date; ``False`` - skip cache;
            ``"refresh"`` - fetch and overwrite cache; ``"force"`` - use cache without staleness check
        brief (bool, optional): If True, return stripped-down interface data for MCP/LLM context
            window optimization. Full data is still fetched; brief mode only affects what is returned.

    Returns:
        dict: Dictionary keyed by device name with interface details.

    This task performs no filtering of data returned by `pynetbox.dcim.interfaces.filter`,
    as a result use netbox REST API explorer to understand resulting data structure, REST
    API browser available at `http://<netbox url>/api/dcim/interfaces/`. In addition
    use nfcli to explore interfaces data:

    ```
    nf#netbox get interfaces devices fceos4 interface-list eth201 | kv

    netbox-worker-1.1.fceos4.eth201.display: eth201
    netbox-worker-1.1.fceos4.eth201.device.name: fceos4
    ...
    ```

    Can also pipe results through `json`, `yaml`, `nested` or `pprint`  formatters to output
    results in  certain format.
    """
    instance = instance or self.default_instance
    nb = self._get_pynetbox(instance, branch=branch)
    devices = devices or []
    cache = self.cache_use if cache is None else cache
    log.info(
        f"{self.name} - Get interfaces: Fetching interfaces for {len(devices)} device(s) from '{instance}'"
    )
    ret = Result(
        task=f"{self.name}:get_interfaces_pynetbox",
        result={d: {} for d in devices},
        resources=[instance],
    )
    filter_params = {}
    all_interfaces = []
    children_by_parent_id = {}  # parent_id -> [child intf, ...]
    member_intf_by_lag_id = {}  # lag_id    -> [member intf, ...]
    ip_by_intf_id = {}
    inv_by_intf_id = {}
    last_updated_by_device = {}

    # build REST filter params
    if devices:
        filter_params["device"] = devices
    if interface_list:
        filter_params["name"] = interface_list
    if interface_regex:
        filter_params["name__regex"] = interface_regex

    if dry_run is True:
        ret.result = {"filter_params": filter_params}
        ret.dry_run = True
        return ret

    job.event(f"retrieving interfaces for {len(devices)} device(s)")

    devices_to_fetch = list(devices)

    if cache == True or cache == "force":
        job.event(f"checking cache for {len(devices)} device(s)")
        # quick REST call to get current last_updated for all matching interfaces
        result = self.bulk_filter(
            nb.dcim.interfaces, **filter_params, fields="name,last_updated,device"
        )
        # build per-device last_updated map
        for intf in result:
            last_updated_by_device.setdefault(intf.device.name, {})[
                intf.name
            ] = intf.last_updated

        self.cache.expire()  # remove expired items from cache
        devices_to_fetch = []
        for device_name, intf_last_updated in last_updated_by_device.items():
            device_cache_key = f"get_interfaces::{device_name}"
            if device_cache_key in self.cache and (
                cache == "force"
                or all(
                    self.cache[device_cache_key]
                    .get(intf_name, {})
                    .get("last_updated")
                    == lu
                    for intf_name, lu in intf_last_updated.items()
                )
            ):
                # serve requested interfaces from cache
                for intf_name in intf_last_updated.keys():
                    ret.result[device_name][intf_name] = self.cache[
                        device_cache_key
                    ][intf_name]
                job.event(
                    f"serving '{device_name}' interfaces from cache ({len(intf_last_updated)} interface(s))"
                )
            else:
                devices_to_fetch.append(device_name)
                job.event(
                    f"'{device_name}' cache miss or stale, fetching fresh data"
                )
    elif cache == False or cache == "refresh":
        pass  # fetch all devices fresh

    # build fetch filter params restricted to devices needing fresh data
    if devices and cache in (True, "force"):
        fetch_filter_params = {**filter_params, "device": devices_to_fetch}
    else:
        fetch_filter_params = filter_params

    # fetch all matching interfaces in one call
    if devices_to_fetch:
        job.event(
            f"fetching interfaces from NetBox for {len(devices_to_fetch)} device(s)"
        )
        all_interfaces = self.bulk_filter(nb.dcim.interfaces, **fetch_filter_params)
        job.event(f"retrieved {len(all_interfaces)} interface(s) from NetBox")

    if not all_interfaces and not any(ret.result.get(d) for d in devices):
        raise Exception(
            f"{self.name} - no interfaces data returned by '{instance}' "
            f"for devices {', '.join(devices)}"
        )

    # build relationship lookup maps from fetched data
    for intf in all_interfaces:
        if intf.parent:
            children_by_parent_id.setdefault(intf.parent.id, []).append(intf)
        if intf.lag:
            member_intf_by_lag_id.setdefault(intf.lag.id, []).append(intf)

    # fetch IP addresses if requested (one bulk call keyed by assigned_object_id)
    if ip_addresses and devices_to_fetch:
        job.event(f"fetching IP addresses for {len(devices_to_fetch)} device(s)")
        for ip in self.bulk_filter(nb.ipam.ip_addresses, device=devices_to_fetch):
            if (
                ip.assigned_object_id
                and ip.assigned_object_type == "dcim.interface"
            ):
                ip_by_intf_id.setdefault(ip.assigned_object_id, []).append(dict(ip))

    # fetch inventory items if requested (one bulk call keyed by component_id)
    if inventory_items and devices_to_fetch:
        job.event(f"fetching inventory items for {len(devices_to_fetch)} device(s)")
        for item in self.bulk_filter(
            nb.dcim.inventory_items, device=devices_to_fetch
        ):
            if item.component_id and item.component_type == "dcim.interface":
                inv_by_intf_id.setdefault(item.component_id, []).append(dict(item))

    # transform pynetbox records into result dict keyed by device / interface name
    for intf in all_interfaces:
        device_name = intf.device.name
        if device_name not in ret.result:  # Netbox issue #16299
            continue

        intf_data = dict(intf)
        # add extra fields
        intf_data["child_interfaces"] = [
            {
                "name": c.name,
                "vrf": c.vrf.name if c.vrf else None,
                "ip_addresses": ip_by_intf_id.get(c.id, []),
            }
            for c in children_by_parent_id.get(intf.id, [])
        ]
        intf_data["member_interfaces"] = [
            m.name for m in member_intf_by_lag_id.get(intf.id, [])
        ]
        intf_data["ip_addresses"] = ip_by_intf_id.get(intf.id, [])
        intf_data["inventory_items"] = inv_by_intf_id.get(intf.id, [])
        ret.result[device_name][intf.name] = intf_data

    # cache freshly fetched interfaces per device
    if cache != False:
        job.event(f"caching interfaces data for {len(devices_to_fetch)} device(s)")
        for device_name in devices_to_fetch:
            if device_name in ret.result:
                cache_key = f"get_interfaces::{device_name}"
                self.cache.set(
                    cache_key,
                    ret.result[device_name],
                    expire=self.cache_ttl,
                )

    if brief:
        ret.result = make_interfaces_brief(ret.result)

    return ret