Skip to content

Nornir Service CFG Task¤

Nornir service cfg task designed to send configuration to devices using SSH and Telnet. Nornir cfg can use Netmiko, Scrapli and NAPALM libraries to configure devices.

Nornir CFG Sample Usage¤

Example of sending configuration commands to devices.

Example

C:\nf>nfcli
Welcome to NorFab Interactive Shell.
nf#

Demo

Nornir CFG Demo

Above sends configuration commands to all Nornir hosts that contain spine or leaf in their hostname as we use FC - "Filter Contains" Nornir hosts targeting filter.

inventory.yaml should be located in same folder where we start nfcli, unless nfcli -i path_to_inventory.yaml flag used. Refer to Getting Started section on how to construct inventory.yaml file

This code is complete and can run as is

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",
        task="cfg",
        kwargs={
            "config": ["ntp server 10.0.0.1", "ntp server 10.0.0.2"],
            "FC": "spine,leaf"              
        }
    )

    pprint.pprint(res)

    nf.destroy()

Refer to Getting Started section on how to construct inventory.yaml file.

Use Different Configuration Plugins¤

NorFab supports various configuration plugins such as netmiko, napalm and scrapli. These plugins enable you to push configurations to a wide range of network devices. Each plugin has its own set of capabilities and requirements, so it is essential to ensure that your Nornir inventory is properly configured for the chosen plugin. This includes specifying the necessary connection parameters and device-specific settings. By leveraging these plugins, you can standardize and automate the configuration management process across different network environments.

Using Dry Run¤

The dry run feature in NorFab allows you to simulate the application of configurations without actually pushing them to the devices. This is particularly useful for testing and validation purposes, as it enables you to verify the correctness of your configurations before making any changes to the network. Additionally, the dry run feature can be used for generating and rendering device configurations, which is beneficial for staging environments where you need to prepare configurations in advance. By using dry run, you can ensure that your configurations are accurate and ready for deployment.

Using Commit Confirmed¤

The commit confirmed feature provides an added layer of safety when pushing configurations to network devices. With this feature, you can apply a configuration with a rollback timer. If the configuration is not explicitly confirmed within the specified time, it will be automatically rolled back to the previous state. This is particularly useful in scenarios where you need to ensure that a configuration change does not negatively impact the network. By using commit confirmed, you can mitigate the risk of configuration errors and ensure network stability.

Sourcing Configuration From Files¤

NorFab allows you to source configurations from text files stored on the broker. This approach enables you to manage configurations as files, making it easier to version control and maintain them. By storing configurations in files, you can apply them as needed, ensuring consistency and repeatability in your configuration management process. This method is particularly useful for large-scale deployments where configurations need to be applied to multiple devices in a controlled and organized manner.

Using Jinja2 Templates¤

Jinja2 templates provide a powerful way to create dynamic configurations based on variables defined in your inventory or passed as job data. By using templates, you can generate configurations that are tailored to the specific requirements of each device. This approach allows you to automate the creation of complex configurations and ensures consistency across your network. Jinja2 templates are highly flexible and can be used to incorporate conditional logic, loops, and other advanced features, making them an essential tool for network automation.

Templating Configuration with Inline Job Data¤

Parsing and Generating Configuration in Templates¤

NorFab supports parsing of device output and the generation of new configurations within same template using parsing results. This capability allows you to create configurations based on the current state of the device, ensuring that your changes are applied accurately and efficiently. By parsing existing configurations, you can extract relevant information and use it to generate new configurations that are consistent with the device's current setup.

Outputting Text Tables¤

The NorFab interactive shell supports the table command, which can be used to format output into text tables. This feature relies on the tabulate module and supports most of its functionalities. By outputting results in table format, you can easily visualize and analyze the data, making it easier to interpret and act upon. This is particularly useful for displaying configuration results in a structured, concise and readable manner.

Formatting Output Results¤

You can format the output results using various options provided by the Nornir worker. The output of the commands can be formatted using the to_dict parameter. When set to True, the results will be returned as a dictionary. When set to False, the results will be returned as a list. In addition add_details argument can be used to control the verbosity of the output and return additional Nornir result information such as:

  • changed flag
  • diff content if supported by plugin
  • failed status
  • exception details if task execution failed with error
  • connection_retry counter to show how many times RetryRunner tried to establish a connection
  • task_retry counter to show how many times RetryRunner tried to run this task

Using Promptless Mode¤

NorFab supports a proprietary promptless mode that can be used with Netmiko. This mode is particularly useful when dealing with devices that do not have a consistent prompt or when the default Netmiko output collection functions are not reliable enough. By enabling promptless mode, you can ensure that configurations are applied accurately and efficiently, even in challenging environments. This feature enhances the robustness of your configuration management process and ensures that your network devices are configured correctly.

NORFAB Nornir CFG Shell Reference¤

NorFab shell supports these command options for Nornir cfg task:

nf#man tree nornir.cfg
root
└── nornir:    Nornir service
    └── cfg:    Configure devices over CLI interface
        ├── timeout:    Job timeout
        ├── workers:    Filter worker to target, default 'all'
        ├── add_details:    Add task details to results
        ├── run_num_workers:    RetryRunner number of threads for tasks execution
        ├── run_num_connectors:    RetryRunner number of threads for device connections
        ├── run_connect_retry:    RetryRunner number of connection attempts
        ├── run_task_retry:    RetryRunner number of attempts to run task
        ├── run_reconnect_on_fail:    RetryRunner perform reconnect to host on task failure
        ├── run_connect_check:    RetryRunner test TCP connection before opening actual connection
        ├── run_connect_timeout:    RetryRunner timeout in seconds to wait for test TCP connection to establish
        ├── run_creds_retry:    RetryRunner list of connection credentials and parameters to retry
        ├── tf:    File group name to save task results to on worker file system
        ├── tf_skip_failed:    Save results to file for failed tasks
        ├── diff:    File group name to run the diff for
        ├── diff_last:    File version number to diff, default is 1 (last)
        ├── progress:    Emit execution progress
        ├── table:    Table format (brief, terse, extend) or parameters or True
        ├── headers:    Table headers
        ├── headers_exclude:    Table headers to exclude
        ├── sortby:    Table header column to sort by
        ├── reverse:    Table reverse the sort by order
        ├── 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
        ├── FM:    Filter hosts by platform
        ├── FX:    Filter hosts excluding them by name
        ├── FN:    Negate the match
        ├── hosts:    Filter hosts to target
        ├── cfg_dry_run:    Dry run cfg function
        ├── *config:    List of configuration commands to send to devices, default 'PydanticUndefined'
        ├── plugin:    Configuration plugin parameters
        │   ├── netmiko:    Use Netmiko plugin to configure devices
        │   │   ├── enable:    Attempt to enter enable-mode
        │   │   ├── exit_config_mode:    Determines whether or not to exit config mode after complete
        │   │   ├── strip_prompt:    Determines whether or not to strip the prompt
        │   │   ├── strip_command:    Determines whether or not to strip the command
        │   │   ├── read_timeout:    Absolute timer to send to read_channel_timing
        │   │   ├── config_mode_command:    The command to enter into config mode
        │   │   ├── cmd_verify:    Whether or not to verify command echo for each command in config_set
        │   │   ├── enter_config_mode:    Do you enter config mode before sending config commands
        │   │   ├── error_pattern:    Regular expression pattern to detect config errors in the output
        │   │   ├── terminator:    Regular expression pattern to use as an alternate terminator
        │   │   ├── bypass_commands:    Regular expression pattern indicating configuration commands, cmd_verify is automatically disabled
        │   │   ├── commit:    Commit configuration or not or dictionary with commit parameters
        │   │   ├── commit_final_delay:    Time to wait before doing final commit
        │   ├── scrapli:    Use Scrapli plugin to configure devices
        │   │   ├── dry_run:    Apply changes or not, also tests if possible to enter config mode
        │   │   ├── strip_prompt:    Strip prompt from returned output
        │   │   ├── failed_when_contains:    String or list of strings indicating failure if found in response
        │   │   ├── stop_on_failed:    Stop executing commands if command fails
        │   │   ├── privilege_level:    Name of configuration privilege level to acquire
        │   │   ├── eager:    Do not read until prompt is seen at each command sent to the channel
        │   │   └── timeout_ops:    Timeout ops value for this operation
        │   └── napalm:    Use NAPALM plugin to configure devices
        │       ├── replace:    Whether to replace or merge the configuration
        │       ├── dry_run:    Apply changes or not, also tests if possible to enter config mode
        │       └── revert_in:    Amount of time in seconds after which to revert the commit
        └── job_data:    Path to YAML file with job data
nf#

* - mandatory/required command argument

Python API Reference¤

Task to send configuration commands to devices using Command Line Interface (CLI)

Parameters:

Name Type Description Default
config list

list of commands to send to devices

required
plugin str

plugin name to use - netmiko, scrapli, napalm

'netmiko'
cfg_dry_run bool

if True, will not send commands to devices but just return them

False
job_data str

URL to YAML file with data or dictionary/list of data to pass on to Jinja2 rendering context

None
add_details bool

if True will add task execution details to the results

False
to_dict bool

default is True - produces dictionary results, if False will produce results list

True
kwargs

additional arguments to pass to the task plugin

{}

Returns:

Type Description
dict

dictionary with the results of the configuration task

Source code in norfab\workers\nornir_worker.py
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
def cfg(
    self,
    config: list,
    plugin: str = "netmiko",
    cfg_dry_run: bool = False,
    to_dict: bool = True,
    add_details: bool = False,
    job_data: str = None,
    **kwargs,
) -> dict:
    """
    Task to send configuration commands to devices using
    Command Line Interface (CLI)

    :param config: list of commands to send to devices
    :param plugin: plugin name to use - ``netmiko``, ``scrapli``, ``napalm``
    :param cfg_dry_run: if True, will not send commands to devices but just return them
    :param job_data: URL to YAML file with data or dictionary/list of data
        to pass on to Jinja2 rendering context
    :param add_details: if True will add task execution details to the results
    :param to_dict: default is True - produces dictionary results, if False
        will produce results list
    :param kwargs: additional arguments to pass to the task plugin
    :return: dictionary with the results of the configuration task
    """
    downloaded_cfg = []
    config = config if isinstance(config, list) else [config]
    filters = {k: kwargs.pop(k) for k in list(kwargs.keys()) if k in FFun_functions}
    ret = Result(task=f"{self.name}:cfg", result={} if to_dict else [])
    timeout = self.current_job["timeout"]

    # decide on what send commands task plugin to use
    if plugin == "netmiko":
        task_plugin = netmiko_send_config
    elif plugin == "scrapli":
        task_plugin = scrapli_send_config
    elif plugin == "napalm":
        task_plugin = napalm_configure
    else:
        raise UnsupportedPluginError(f"Plugin '{plugin}' not supported")

    self.nr.data.reset_failed_hosts()  # reset failed hosts
    filtered_nornir = FFun(self.nr, **filters)  # filter hosts

    # check if no hosts matched
    if not filtered_nornir.inventory.hosts:
        msg = (
            f"{self.name} - nothing to do, no hosts matched by filters '{filters}'"
        )
        ret.messages.append(msg)
        log.debug(msg)
        return ret

    job_data = self.load_job_data(job_data)

    nr = self._add_processors(filtered_nornir, kwargs)  # add processors

    # render config using Jinja2 on a per-host basis
    for host in nr.inventory.hosts.values():
        rendered = self.render_jinja2_templates(
            templates=config,
            context={
                "host": host,
                "norfab": self.client,
                "nornir": self,
                "job_data": job_data,
            },
            filters=self.add_jinja2_filters(),
        )
        host.data["__task__"] = {"config": rendered}

    # run task
    log.debug(
        f"{self.name} - sending config commands '{config}', kwargs '{kwargs}', is cfg_dry_run - '{cfg_dry_run}'"
    )
    if cfg_dry_run is True:
        result = nr.run(
            task=nr_test, use_task_data="config", name="cfg_dry_run", **kwargs
        )
    else:
        with self.connections_lock:
            result = nr.run(task=task_plugin, **kwargs)
        ret.changed = True

    ret.result = ResultSerializer(result, to_dict=to_dict, add_details=add_details)

    # remove __task__ data
    for host_name, host_object in nr.inventory.hosts.items():
        _ = host_object.data.pop("__task__", None)

    self.watchdog.connections_update(nr, plugin)
    self.watchdog.connections_clean()

    return ret