Skip to content

Netbox Update Interfaces Description Task¤

task api name: update_interfaces_description

Updates the description field of interfaces, console ports, and console server ports for one or more devices in NetBox. Supports two mutually usable modes: template mode (description_template) renders descriptions dynamically using Jinja2 with live connection context, and static mode (descriptions) applies a fixed mapping of interface names to description strings.

How it Works¤

  1. Client submits update_interfaces_description request to NetBox worker
  2. Worker resolves the target NetBox instance and optionally the branch
  3. If description_template is provided, the worker fetches all interface connections for the given devices via get_connections
  4. For each interface, the Jinja2 template is rendered with the connection context (device, interface, remote device, cable attributes, etc.)
  5. If descriptions dict is provided, the worker iterates over the given device list and applies the fixed description values directly
  6. In dry-run mode — the before (-) / after (+) diff is returned without writing to NetBox
  7. Otherwise, the new description is saved to NetBox

Prerequisites¤

  • The devices must already exist in NetBox.
  • Only interfaces, console ports, console server ports and power outlet ports are supported as port types.

Branching Support¤

update_interfaces_description is branch-aware. Pass branch=<name> to write all changes into a NetBox Branching Plugin branch instead of main.

Dry Run Mode¤

dry_run=True returns the before/after description diff without any NetBox writes:

{
    "<device>": {
        "<interface>": {
            "-": "<current description>",
            "+": "<new description>",
        },
        ...
    },
    ...
}

Template Mode¤

When description_template is provided, the Jinja2 template is rendered once per interface using the full connection context. The template can be an inline string or a remote NorFab file reference (nf://path/to/template.txt).

Jinja2 context variables available in the template:

  • device — pynetbox dcim.device object
  • interface — pynetbox interface/console port/console server port object
  • remote_device — string
  • remote_interface — string
  • termination_type — string
  • cable — dictionary of directly attached cable attributes:
    • type
    • status
    • tenant — dictionary {name: tenant_name}
    • label
    • tags — list of {name: tag_name} dictionaries
    • custom_fields — dictionary with custom fields data
    • peer_termination_type
    • peer_device
    • peer_interface

Example template:

{{ remote_device }}:{{ remote_interface }}

Static Mode¤

When descriptions dict is provided, the same mapping is applied to all devices in the devices list. Only interfaces that exist in NetBox are updated — missing interfaces are silently skipped.

descriptions = {
    "Ethernet1": "uplink to spine-1",
    "Ethernet2": "uplink to spine-2",
}

Examples¤

Update interface descriptions using a Jinja2 template:

nf#netbox update interfaces description devices ceos-leaf-1 description-template "{{ remote_device }}:{{ remote_interface }}"

Filter interfaces by regex pattern:

nf#netbox update interfaces description devices ceos-leaf-1 description-template "{{ remote_device }}:{{ remote_interface }}" interface-regex "Ethernet.*"

Dry run — preview changes without writing:

nf#netbox update interfaces description devices ceos-leaf-1 description-template "{{ remote_device }}:{{ remote_interface }}" dry-run

Update descriptions in a NetBox branch:

nf#netbox update interfaces description devices ceos-leaf-1 description-template "{{ remote_device }}:{{ remote_interface }}" branch my-branch
from norfab.core.nfapi import NorFab

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

# update descriptions using a Jinja2 template
result = client.run_job(
    "netbox",
    "update_interfaces_description",
    workers="any",
    kwargs={
        "devices": ["ceos-leaf-1", "ceos-leaf-2"],
        "description_template": "{{ remote_device }}:{{ remote_interface }}",
    },
)

# filter interfaces by regex and use a remote template
result = client.run_job(
    "netbox",
    "update_interfaces_description",
    workers="any",
    kwargs={
        "devices": ["ceos-leaf-1"],
        "description_template": "nf://templates/intf_desc.j2",
        "interface_regex": "Ethernet.*",
    },
)

# dry run — preview diff without writing
result = client.run_job(
    "netbox",
    "update_interfaces_description",
    workers="any",
    kwargs={
        "devices": ["ceos-leaf-1"],
        "description_template": "{{ remote_device }}:{{ remote_interface }}",
        "dry_run": True,
    },
)

# static descriptions dict applied to multiple devices
result = client.run_job(
    "netbox",
    "update_interfaces_description",
    workers="any",
    kwargs={
        "devices": ["ceos-leaf-1", "ceos-leaf-2"],
        "descriptions": {
            "Ethernet1": "uplink to spine-1",
            "Ethernet2": "uplink to spine-2",
        },
    },
)

# update into a NetBox branch
result = client.run_job(
    "netbox",
    "update_interfaces_description",
    workers="any",
    kwargs={
        "devices": ["ceos-leaf-1"],
        "description_template": "{{ remote_device }}:{{ remote_interface }}",
        "branch": "my-branch",
    },
)

nf.destroy()

NORFAB Netbox Update Interfaces Description Command Shell Reference¤

NorFab shell supports these command options for the Netbox update_interfaces_description task:

nf# man tree netbox.update.interfaces.description
root
└── netbox:    Netbox service
    └── update:    Update Netbox objects
        └── interfaces:    Update interfaces
            └── description:    Updates the description of interfaces for specified devices in NetBox
                ├── timeout:    Job timeout
                ├── workers:    Filter worker to target, default 'any'
                ├── verbose-result:    Control output details, default 'False'
                ├── progress:    Display progress events, default 'True'
                ├── instance:    Netbox instance name to target
                ├── branch:    Branching plugin branch name to use
                ├── dry-run:    Return diff without writing to NetBox
                ├── devices:    Device names to update interfaces for
                ├── description-template:    Jinja2 template to render descriptions
                └── interface-regex:    Regex pattern to match interfaces and ports
nf#

Python API Reference¤

Updates the description of interfaces for specified devices in NetBox.

This method retrieves interface connections for the given devices, renders new descriptions using a Jinja2 template, and updates the interface descriptions in NetBox accordingly.

Only interfaces, console ports and console server ports supported.

Jinja2 environment receives these context variables for description template rendering:

  • device - pynetbox dcim.device object
  • interface - pynetbox object - dcim/interface, dcip.consoleport, dcim.consoleserverport - depending on what kind of interface is that.
  • remote_device - string
  • remote_interface - string
  • termination_type - string
  • cable - dictionary of directly attached cable attributes:
    • type
    • status
    • tenant - dictionary of {name: tenant_name}
    • label
    • tags - list of {name: tag_name} dictionaries
    • custom_fields - dictionary with custom fields data
    • peer_termination_type
    • peer_device
    • peer_interface

Parameters:

Name Type Description Default
job Job

The job context for logging and event handling.

required
devices list

List of device names to update interfaces for.

required
description_template str

Jinja2 template string for the interface description. Can reference remote template using nf://path/to/template.txt.

None
descriptions dict

Dictionary keyed by interface names with values being interface description strings

None
interfaces Union[None, list]

Specific interfaces to update.

None
interface_regex Union[None, str]

Regex pattern to filter interfaces.

None
instance Union[None, str]

NetBox instance identifier.

None
dry_run bool

If True, performs a dry run without saving changes.

False
timeout int

Timeout for NetBox API requests.

60
branch str

Branch name for NetBox instance.

None

Returns:

Name Type Description
Result Result

An object containing the outcome of the update operation, including before and after descriptions.

Source code in norfab\workers\netbox_worker\interfaces_tasks.py
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
@Task(
    fastapi={"methods": ["PATCH"], "schema": NetboxFastApiArgs.model_json_schema()},
    input=UpdateInterfacesDescriptionInput,
)
def update_interfaces_description(
    self,
    job: Job,
    devices: list,
    description_template: str = None,
    descriptions: dict = None,
    interfaces: Union[None, list] = None,
    interface_regex: Union[None, str] = None,
    instance: Union[None, str] = None,
    dry_run: bool = False,
    timeout: int = 60,
    branch: str = None,
) -> Result:
    """
    Updates the description of interfaces for specified devices in NetBox.

    This method retrieves interface connections for the given devices, renders
    new descriptions using a Jinja2 template, and updates the interface descriptions
    in NetBox accordingly.

    Only interfaces, console ports and console server ports supported.

    Jinja2 environment receives these context variables for description template rendering:

    - device - pynetbox `dcim.device` object
    - interface - pynetbox object - `dcim/interface`, `dcip.consoleport`,
        `dcim.consoleserverport` - depending on what kind of interface is that.
    - remote_device - string
    - remote_interface - string
    - termination_type - string
    - cable - dictionary of directly attached cable attributes:
        - type
        - status
        - tenant - dictionary of `{name: tenant_name}`
        - label
        - tags - list of `{name: tag_name}` dictionaries
        - custom_fields - dictionary with custom fields data
        - peer_termination_type
        - peer_device
        - peer_interface

    Args:
        job (Job): The job context for logging and event handling.
        devices (list): List of device names to update interfaces for.
        description_template (str): Jinja2 template string for the interface description.
            Can reference remote template using `nf://path/to/template.txt`.
        descriptions (dict): Dictionary keyed by interface names with values being interface
            description strings
        interfaces (Union[None, list], optional): Specific interfaces to update.
        interface_regex (Union[None, str], optional): Regex pattern to filter interfaces.
        instance (Union[None, str], optional): NetBox instance identifier.
        dry_run (bool, optional): If True, performs a dry run without saving changes.
        timeout (int, optional): Timeout for NetBox API requests.
        branch (str, optional): Branch name for NetBox instance.

    Returns:
        Result: An object containing the outcome of the update operation, including
            before and after descriptions.
    """
    result = {}
    instance = instance or self.default_instance
    ret = Result(
        task=f"{self.name}:update_interfaces_description",
        result=result,
        resources=[instance],
    )
    nb = self._get_pynetbox(instance, branch=branch)
    log.info(
        f"{self.name} - Update interfaces description: Updating descriptions for {len(devices)} device(s) in '{instance}'"
    )

    job.event(f"updating interface descriptions for {len(devices)} device(s)")

    if description_template:
        # get list of all interfaces connections
        nb_connections = self.get_connections(
            job=job,
            devices=devices,
            interface_regex=interface_regex,
            instance=instance,
        )
        # produce interfaces description and update it
        while nb_connections.result:
            device, device_connections = nb_connections.result.popitem()
            ret.result.setdefault(device, {})
            job.event(
                f"processing {len(device_connections)} interface(s) for '{device}'"
            )
            for interface, connection in device_connections.items():
                job.event(f"{device}:{interface} updating description")
                if connection["termination_type"] == "consoleport":
                    api_endpoint = nb.dcim.console_ports
                elif connection["termination_type"] == "consoleserverport":
                    api_endpoint = nb.dcim.console_server_ports
                elif connection["termination_type"] == "powerport":
                    api_endpoint = nb.dcim.power_ports
                elif connection["termination_type"] == "poweroutlet":
                    api_endpoint = nb.dcim.power_outlets
                else:
                    api_endpoint = nb.dcim.interfaces
                nb_interface = api_endpoint.get(device=device, name=interface)
                nb_device = nb.dcim.devices.get(name=device)
                rendered_description = self.jinja2_render_templates(
                    templates=[description_template],
                    context={
                        "device": nb_device,
                        "interface": nb_interface,
                        **connection,
                    },
                )
                rendered_description = str(rendered_description).strip()
                ret.result[device][interface] = {
                    "-": str(nb_interface.description),
                    "+": rendered_description,
                }
                nb_interface.description = rendered_description
                if dry_run is False:
                    nb_interface.save()
    if descriptions:
        job.event(
            f"applying {len(descriptions)} description(s) to {len(devices)} device(s)"
        )
        for device in devices:
            ret.result.setdefault(device, {})
            for interface, description in descriptions.items():
                nb_interface = nb.dcim.interfaces.get(name=interface, device=device)
                if nb_interface:
                    ret.result[device][interface] = {
                        "-": str(nb_interface.description),
                        "+": description,
                    }
                    nb_interface.description = description
                    if dry_run is False:
                        nb_interface.save()
    return ret