Skip to content

Nornir Service Runtime Inventory Task¤

task api name: runtime_inventory

The Nornir service runtime_inventory task works with Nornir inventory content at runtime. It uses nornir-salt InventoryFun functions to create, read, update, delete, and load hosts without restarting the worker.

Connection side effect: create_host/create, delete_host/delete, and load close connections for all hosts on the targeted Nornir worker before changing the inventory. This includes connections to hosts unrelated to the requested change and hosts marked failed. Subsequent tasks reconnect as needed.

Inputs¤

Parameter Required Description
action Yes Inventory action to perform.
name Required for host actions Host name to create, read, update, or delete.
hostname No Hostname or IP address used for connections.
platform No Host platform used by connection plugins.
username, password, port No Host connection parameters.
groups No Groups associated with the host.
data No Arbitrary host data.
connection_options No Nornir connection options.
workers No Nornir workers to target.

Output¤

The task returns action-specific inventory data. Create, update, delete, and load actions commonly return booleans or per-host status. Read actions return inventory content.

Examples¤

Example

Create a runtime host:

nf# nornir inventory create-host name foobar hostname 192.0.2.10 platform arista_eos username admin password admin

Read runtime host inventory:

nf# nornir inventory read-host name foobar

Load hosts from a Containerlab lab into a Nornir worker:

nf# nornir inventory load containerlab clab-workers containerlab-worker-1 workers nornir-worker-1 lab-name three-routers-lab

Context manager - create and read a runtime host:

import pprint

from norfab.core.nfapi import NorFab

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

    create_result = client.run_job(
        service="nornir",
        task="runtime_inventory",
        workers=["nornir-worker-1"],
        kwargs={
            "action": "create_host",
            "name": "foobar",
            "hostname": "192.0.2.10",
            "platform": "arista_eos",
            "username": "admin",
            "password": "admin",
        },
    )

    read_result = client.run_job(
        service="nornir",
        task="runtime_inventory",
        workers=["nornir-worker-1"],
        kwargs={
            "action": "read_host",
            "name": "foobar",
        },
    )

    pprint.pprint(create_result)
    pprint.pprint(read_result)

Direct lifecycle - load inventory from Containerlab:

import pprint

from norfab.core.nfapi import NorFab

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

    result = client.run_job(
        service="nornir",
        task="nornir_inventory_load_containerlab",
        workers=["nornir-worker-1"],
        kwargs={
            "lab_name": "three-routers-lab",
            "clab_workers": ["containerlab-worker-1"],
            "groups": ["containerlab"],
        },
    )

    pprint.pprint(result)
finally:
    nf.destroy()

Supported actions are:

  • create_host or create - creates new host or replaces existing host object
  • read_host or read - read host inventory content
  • update_host or update - non recursively update host attributes if host exists in Nornir inventory, do not create host if it does not exist
  • delete_host or delete - deletes host object from Nornir Inventory
  • load - to simplify calling multiple functions
  • read_inventory - read inventory content for groups, default and hosts
  • read_host_data - to return host's data under provided path keys
  • list_hosts - return a list of inventory's host names
  • list_hosts_platforms - return a dictionary of hosts' platforms
  • update_defaults - non recursively update defaults attributes
  • load - load Nornir inventory from external sources

Notes¤

Create Host Output Example¤

nf#nornir inventory create-host name foobar
--------------------------------------------- Job Events -----------------------------------------------
15-Feb-2025 11:12:38.908 d42e073070b94d408225af2a880d1d26 job started
15-Feb-2025 11:12:38.939 INFO nornir-worker-5 running nornir.runtime_inventory  - Performing 'create_host' action
15-Feb-2025 11:12:39.162 d42e073070b94d408225af2a880d1d26 job completed in 0.254 seconds

--------------------------------------------- Job Results --------------------------------------------

{
    "nornir-worker-5": {
        "foobar": true
    }
}
nf#

Nornir and Containerlab Services Integration¤

Nornir Service supports loading hosts inventory from running Containerlab labs using nornir_inventory_load_containerlab task. This is useful to easily onboard Containerlab environments into Nornir and helps with automation. Internally Nornir service uses Containerlab Service to fetch running containers details and construct Nornir inventory.

Set load_netbox=True to load device data, interfaces with IP addresses and inventory items, connections, circuits with interface details, and BGP peerings. Worker Netbox inventory settings are ignored, and reads bypass caches by default. A dictionary overrides these defaults, for example:

client.run_job(
    service="nornir",
    task="nornir_inventory_load_containerlab",
    workers="nornir-worker-1",
    kwargs={
        "lab_name": "demo-4-routers",
        "clab_workers": "containerlab-worker-1",
        "load_netbox_branch": "demo",
        "load_netbox_instance": "prod",
        "load_netbox": {
            "interfaces": {"ip_addresses": True},
            "connections": True,
            "bgp_peerings": True,
        },
        "dry_run": True,
    },
)

Only imported Containerlab host names are queried; supplied Netbox devices and filters do not widen that selection. Netbox host data is merged while the Containerlab SSH endpoints, platforms, credentials, and groups are preserved. An empty dictionary enables all default enrichment options. interfaces=True alone does not include assigned IPs; request interfaces={"ip_addresses": True} to include them. The CLI boolean form is nornir inventory load containerlab load-netbox with the usual worker and lab arguments.

Enrichment errors or missing Netbox hosts fail the task before inventory is updated. A dry run with enrichment returns the first successful Containerlab worker's combined inventory without changing Nornir. The default load_netbox=False retains the existing loading behavior unless a nonempty load_netbox_branch or load_netbox_instance enables enrichment.

Use load_netbox_branch (CLI: load-netbox-branch) to select a branch and enable Netbox loading. It overrides the branch in supplied Netbox options. When omitted, the branch from those options is used.

Use load_netbox_instance (CLI: load-netbox-instance) to select the Netbox instance and enable loading. It overrides the instance in supplied options. When omitted, the supplied instance or Netbox service's default instance is used.

Example

nf#nornir inventory load containerlab clab-workers containerlab-worker-1 workers nornir-worker-1 lab-name three-routers-lab
--------------------------------------------- Job Events -----------------------------------------------
05-May-2025 21:32:07.155 ed210f6c91ac40ada02149118eede2c9 job started
05-May-2025 21:32:07.172 INFO nornir-worker-1 running nornir.nornir_inventory_load_containerlab  - Pulling Containerlab 'three-routers-lab' lab inventory from 'containerlab-worker-1' workers
05-May-2025 21:32:07.393 INFO nornir-worker-1 running nornir.nornir_inventory_load_containerlab  - Pulled Containerlab 'three-routers-lab' lab inventory
05-May-2025 21:32:07.399 INFO nornir-worker-1 running nornir.nornir_inventory_load_containerlab  - Merged Containerlab 'three-routers-lab' lab inventory with Nornir runtime inventory
05-May-2025 21:32:07.916 ed210f6c91ac40ada02149118eede2c9 job completed in 0.76 seconds

--------------------------------------------- Job Results --------------------------------------------

nornir-worker-1:
    True
nf#
import pprint

from norfab.core.nfapi import NorFab

if __name__ == "__main__":
    nf = NorFab(inventory="inventory.yaml")
    nf.start()

    client = nf.make_client()

    res = client.run_job(
        service="nornir",
        workers=["nornir-worker-1"],
        task="nornir_inventory_load_containerlab",
        kwargs={
            "lab_name": "three-routers-lab",
            "clab_workers": ["containerlab-worker-1"],
        }
    )

    pprint.pprint(res)

    nf.destroy()

NORFAB Nornir Runtime Inventory Shell Reference¤

NorFab shell supports these command options for Nornir runtime_inventory task:

nf# man tree nornir.inventory
root
└── nornir:    Nornir service
    └── inventory:    Work with Nornir inventory
        ├── create-host:    Create new host
        │   ├── timeout:    Job timeout
        │   ├── workers:    Nornir workers to target, default 'any'
        │   ├── verbose-result:    Control output details, default 'False'
        │   ├── *name:    Name of the host
        │   ├── username:    Host connections username
        │   ├── password:    Host connections password
        │   ├── platform:    Host platform recognized by connection plugin
        │   ├── hostname:    Hostname of the host to initiate connection with, IP address or FQDN
        │   ├── port:    TCP port to initiate connection with, default '22'
        │   ├── connection-options:    JSON string with connection options
        │   ├── groups:    List of groups to associate with this host
        │   ├── data:    JSON string with arbitrary host data
        │   └── progress:    Display progress events, default 'True'
        ├── update-host:    Update existing host details
        │   ├── timeout:    Job timeout
        │   ├── workers:    Nornir workers to target, default 'all'
        │   ├── verbose-result:    Control output details, default 'False'
        │   ├── *name:    Name of the host
        │   ├── username:    Host connections username
        │   ├── password:    Host connections password
        │   ├── platform:    Host platform recognized by connection plugin
        │   ├── hostname:    Hostname of the host to initiate connection with, IP address or FQDN
        │   ├── port:    TCP port to initiate connection with, default '22'
        │   ├── connection-options:    JSON string with connection options
        │   ├── groups:    List of groups to associate with this host
        │   ├── groups-action:    Action to perform with groups, default 'append'
        │   ├── data:    JSON string with arbitrary host data
        │   └── progress:    Display progress events, default 'True'
        ├── delete-host:    Delete host from inventory
        │   ├── timeout:    Job timeout
        │   ├── workers:    Nornir workers to target, default 'all'
        │   ├── verbose-result:    Control output details, default 'False'
        │   ├── *name:    Name of the host
        │   └── progress:    Display progress events, default 'True'
        ├── read-host-data:    Return host data at given dor-separated key path
        │   ├── timeout:    Job timeout
        │   ├── workers:    Nornir workers to target, default 'all'
        │   ├── verbose-result:    Control output details, default 'False'
        │   ├── FO:    Filter hosts using Filter Object
        │   ├── FB:    Filter hosts by name using Glob Patterns
        │   ├── FH:    Filter hosts by hostname
        │   ├── FC:    Filter hosts containment of pattern in name
        │   ├── FR:    Filter hosts by name using Regular Expressions
        │   ├── FG:    Filter hosts by group
        │   ├── FP:    Filter hosts by hostname using IP Prefix
        │   ├── FL:    Filter hosts by names list
        │   ├── FX:    Filter hosts excluding them by name
        │   ├── FN:    Negate the match
        │   ├── *keys:    Dot separated path within host data, examples: config.interfaces.Lo0
        │   └── progress:    Display progress events, default 'True'
        └── load:    Load inventory from external source
            └── containerlab:    Load inventory from running Containerlab lab(s)
                ├── timeout:    Job timeout
                ├── *workers:    Nornir workers to load inventory into
                ├── verbose-result:    Control output details, default 'False'
                ├── clab-workers:    Containerlab workers to load inventory from
                ├── progress:    Display progress events, default 'True'
                ├── lab-name:    Name of Containerlab lab to load hosts' inventory
                ├── groups:    List of Nornir groups to associate with hosts
                ├── use-default-credentials:    Use Containerlab default credentials for all hosts
                └── dry-run:    Do not refresh Nornir, only return pulled inventory
nf#

* - mandatory/required command argument

Python API Reference¤

Task to work with Nornir runtime (in-memory) inventory.

Create, delete, and load actions close all connections for all hosts on this worker before changing the inventory.

Supported actions:

  • create_host or create - creates new host or replaces existing host object
  • read_host or read - read host inventory content
  • update_host or update - non recursively update host attributes if host exists in Nornir inventory, do not create host if it does not exist
  • delete_host or delete - deletes host object from Nornir Inventory
  • load - to simplify calling multiple functions
  • read_inventory - read inventory content for groups, default and hosts
  • read_host_data - to return host's data under provided path keys
  • list_hosts - return a list of inventory's host names
  • list_hosts_platforms - return a dictionary of hosts' platforms
  • update_defaults - non recursively update defaults attributes

Parameters:

Name Type Description Default
job Job

NorFab Job object containing relevant metadata

required
action str

action to perform on inventory

required
kwargs Any

arguments to use with the calling action

{}
Source code in norfab\workers\nornir_worker\inventory_tasks.py
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
@Task(
    fastapi={"methods": ["POST"]},
    input=RuntimeInventoryInput,
    output=RuntimeInventoryResult,
    mcp={
        "annotations": {
            "title": "Update Runtime Inventory",
            "readOnlyHint": False,
            "destructiveHint": True,
            "idempotentHint": False,
            "openWorldHint": False,
        }
    },
)
def runtime_inventory(self, job: Job, action: str, **kwargs: Any) -> Result:
    """
    Task to work with Nornir runtime (in-memory) inventory.

    Create, delete, and load actions close all connections for all hosts on this
    worker before changing the inventory.

    Supported actions:

    - `create_host` or `create` - creates new host or replaces existing host object
    - `read_host` or `read` - read host inventory content
    - `update_host` or `update` - non recursively update host attributes if host exists
        in Nornir inventory, do not create host if it does not exist
    - `delete_host` or `delete` - deletes host object from Nornir Inventory
    - `load` - to simplify calling multiple functions
    - `read_inventory` - read inventory content for groups, default and hosts
    - `read_host_data` - to return host's data under provided path keys
    - `list_hosts` - return a list of inventory's host names
    - `list_hosts_platforms` - return a dictionary of hosts' platforms
    - `update_defaults` - non recursively update defaults attributes

    Args:
        job: NorFab Job object containing relevant metadata
        action: action to perform on inventory
        kwargs: arguments to use with the calling action
    """
    # clean up kwargs
    _ = kwargs.pop("progress", None)
    job.event(f"performing '{action}' action")
    with self.connections_lock:
        if action in {"delete_host", "delete", "create_host", "create", "load"}:
            self.nr.run(
                task=nr_connections, call="close", conn_name="all", on_failed=True
            )
            self.watchdog.connections_data.clear()
        return Result(result=InventoryFun(self.nr, call=action, **kwargs))