Table of Contents
- Overview
- Core Components
- Runner Plugins
- Example Runner Configuration
- How Runner Improves Automation
- Sample Usage in Python
- Best Practices
- Troubleshooting
- Conclusion
Nornir Automation: Runner Overview
What Is the Nornir Runner?
The Runner in Nornir is the core component responsible for executing tasks on network devices efficiently. Acting as Nornir’s “task dispatcher,” it determines how and when each job is sent to your inventory of devices. The Runner is configurable so you can choose the strategy that best fits the nature and scale of your automation.
- It enables parallel or sequential execution of tasks.
- It manages resources like threads or processes to maximize performance.
- It aggregates and structures results for further processing or reporting.
Why You Need to Know About the Runner
- Performance Optimization: The Runner directly impacts how quickly automation jobs finish. For larger environments, proper use of the Runner can save hours of operational time.
- Reliability: With concurrency controls, the Runner ensures that task failures are isolated and do not affect the rest of your workflow.
- Scalability: The Runner allows Nornir to handle everything from a handful to thousands of network devices without fundamental changes to your code or automation framework.
- Flexibility: You can tailor how tasks are distributed, letting you balance speed, resource consumption, and safety depending on your current automation scenario.
How the Runner Works
- Configuration-Driven: You set up the Runner in your Nornir configuration file or dynamically in Python, specifying details like the runner type (threaded or serial) and how many tasks can run in parallel.
- Execution Strategy: The Runner takes your submitted task and, based on your configuration:
- Executes it concurrently across multiple hosts (threaded)
- Or processes one host at a time (serial)
- Thread/Worker Management: It launches and manages worker threads or processes that perform each device interaction. This spreads the load across available CPU resources to speed up task completion.
- Result Collection: As workers finish, the Runner gathers the results and structures them for easy consumption, troubleshooting, or logging.
- Error Isolation: If a task fails on one device, the Runner keeps others running, ensuring resilience and minimizing risk.
In short, the Nornir Runner is the engine that powers fast, safe, and scalable network automation by giving you granular control over how tasks are executed across your infrastructure. Whether you’re just starting automation or managing vast multi-vendor networks, understanding the Runner is essential for building efficient, maintainable workflows.
Core Components
The Nornir Runner is composed of several core components that define how tasks are executed concurrently across network devices. Understanding these elements is essential for customizing concurrency and optimizing performance:
-
Runner Plugin:
Defines the execution strategy Nornir uses. Available plugins include
threaded
for concurrent execution andserial
for sequential task execution. This affects how commands are dispatched to the inventory hosts. - num_workers: Sets the number of threads (or workers) available to execute tasks concurrently. A higher value increases potential performance for large inventories but must be balanced against system resources.
- Task Dispatcher: Manages the delegation of tasks from Nornir to each host. This component dynamically assigns tasks to worker threads based on the runner configuration.
- Result Aggregator: Collects and organizes results from all worker threads after execution. This ensures a consistent output structure, even when tasks run in parallel.
Runner Plugins
Nornir provides different runner plugins that control how tasks are executed across hosts. These plugins define whether tasks are executed in parallel, in series, or with custom logic. Selecting the right plugin is key to optimizing performance based on your network size and operational requirements:
- threaded (Default): Executes tasks concurrently across hosts by using Python’s threading model. This is ideal for processing multiple devices in parallel, especially for read-only commands and configuration gathering. It significantly reduces execution time and is best suited for medium to large inventories.
- serial: Runs tasks sequentially from one host to the next. This is useful for debugging, controlled testing, or deployments where actions need to be taken one device at a time. While slower, it ensures strict task ordering.
You can define your preferred runner plugin in the nornir.yaml
configuration file:
runner: plugin: threaded options: num_workers: 10
This configuration sets Nornir to use the threaded runner with 10 parallel workers. Adjust num_workers
based on the size of your inventory and available system resources.
Example Runner Configuration
Configuring the Nornir Runner can be done using a YAML configuration file or programmatically in Python. The following examples demonstrate common ways to specify runner settings, helping you fine-tune how tasks are executed across your hosts:
-
YAML Configuration Example:
Define the runner settings in your
config.yaml
file. This is user-friendly and keeps your configuration organized:runner: plugin: threaded options: num_workers: 10
This example sets the runner to use the
threaded
plugin and allows up to 10 parallel workers. Adjustnum_workers
based on your needs and system resources. -
Python Initialization Example:
You can also set runner options directly when initializing Nornir in your Python script:
from nornir import InitNornir nr = InitNornir( runner={ "plugin": "threaded", "options": {"num_workers": 20} } )
This approach provides flexibility, especially for dynamic or programmatic configuration.
-
Combining File and Code:
Override settings from the config file by specifying runner options directly in code:
nr = InitNornir( config_file="config.yaml", runner={"plugin": "threaded", "options": {"num_workers": 50}} )
Here, the
num_workers
is set to 50 in code, overriding the value inconfig.yaml
.
Remember: The runner’s configuration controls how tasks are distributed across your devices. Tuning num_workers
to match your environment ensures efficient, reliable automation.
How Runner Improves Automation
The Nornir Runner plays a crucial role in making network automation faster, more reliable, and easier to manage. Here’s how it elevates your automation workflows:
- Parallel Task Execution: The runner utilizes multi-threading to execute tasks across multiple devices at the same time. This dramatically reduces the overall runtime, especially when managing large inventories or performing repetitive operations.
- Consistent and Reliable Results: Tasks run independently on each device, so a failure in one thread does not impact others. This isolation ensures that partial failures don’t bring down your entire automation job.
- Efficient Resource Utilization: By controlling the number of worker threads, you can match the concurrency level to your hardware capabilities and the needs of your environment. This helps optimize resource usage during automation runs.
- Scalability: The runner makes it possible to scale automation from small environments to thousands of devices without rewriting your code or restructuring your workflows.
- Improved Troubleshooting: With built-in logging and structured result aggregation, it becomes easier to identify, debug, and resolve issues when tasks do not execute as expected.
- Minimizes Human Error: Automated, parallel execution limits the scope for manual mistakes and simplifies complex, repetitive processes—freeing network teams to focus on more strategic tasks.
By leveraging the Runner, network engineers can ensure that automation is not only faster and more scalable but also safer and easier to operate in real-world production environments.
Sample Usage in Python
Using the Nornir Runner in Python is straightforward. Here’s a basic example of using the threaded
runner plugin to send a command to devices in your inventory using Netmiko. This demonstrates how concurrency is baked into the task execution layer:
from nornir import InitNornir from nornir_netmiko.tasks import netmiko_send_command from nornir_utils.plugins.functions import print_result # Initialize Nornir with runner configuration nr = InitNornir( config_file="config.yaml", runner={ "plugin": "threaded", "options": {"num_workers": 10} } ) # Define a task to execute on remote devices def show_version(task): task.run(task=netmiko_send_command, command_string="show version") # Run the task across all hosts result = nr.run(task=show_version) # Print out the results print_result(result)
This script initializes Nornir with a threaded
runner and 10 workers, allowing tasks to run concurrently across devices. Each device will execute the same task independently, and results will be aggregated and printed in structured output.
You can increase num_workers
based on the number of devices you're automating and your system's resource availability. Fine-tuning this allows for optimized execution with minimal configuration changes.
Best Practices
To get the most out of the Nornir Runner in your automation workflows, follow these best practices to improve performance, maintain control, and avoid common issues:
-
Start with Serial Execution for Testing:
Use the
serial
runner during initial task testing and debugging. It allows better visibility into each step and easier troubleshooting without multiple threads interfering. -
Optimize
num_workers
per Environment: Match the number of worker threads to your system capacity and the size of your host inventory. Too many workers can overwhelm device APIs or local CPU/memory. -
Use Threaded Runners in Production:
For production-scale rollouts or data gathering from large inventories, use the
threaded
runner to drastically reduce execution time. - Group Tasks with Similar Resource Requirements: Avoid mixing resource-heavy operations with lighter ones in the same execution cycle. This helps maintain balanced load distribution across threads.
- Build Error Handling into Task Results: Use the result data structure to catch and handle failed task outputs gracefully without stopping other threaded tasks.
-
Log Results Consistently:
Implement structured logging using
print_result()
or customized log writers. This keeps threaded task output readable and easier to track across multiple concurrent executions. - Test at Scale Before Full Rollouts: Validate the concurrency level and result consistency in a staging environment before running task sets on production devices at scale.
Following these best practices will help you create stable, efficient, and predictable automation workflows with the Nornir Runner.
Troubleshooting
Even with robust automation frameworks, issues can arise that impact task execution, concurrency, or overall reliability. This section outlines common troubleshooting steps and practical tips to help you quickly diagnose and resolve problems with the Nornir Runner:
-
Tasks Not Executing Concurrently:
-
Verify your runner configuration in
config.yaml
(or equivalent). Ensure theplugin
is set tothreaded
andnum_workers
is greater than 1. - Check for code-level overrides when initializing Nornir, which may supersede file-based settings.
-
Verify your runner configuration in
-
Performance Bottlenecks or Slow Execution:
-
Increase
num_workers
if hardware allows, but do not exceed resource limitations of your system or managed devices. - Evaluate external dependencies (e.g., device response times, network latency, API rate limits) that may throttle parallel processing.
-
Increase
-
Unexpected Task Failures or Incomplete Results:
- Review exception and error messages in Nornir’s result output and logs to identify which device(s) or task(s) failed.
- Ensure device credentials are correct and that all managed nodes are online and reachable.
-
Error Handling in Threaded Mode:
- Inspect the output structure for failed hosts—threaded runners keep other workers active even if one fails.
- Implement custom error handlers in your task logic to manage and document failures gracefully.
-
Logging and Diagnostic Data:
- Enable verbose logging for deeper insights into runner activity and task execution order.
-
Use dedicated log files or structured output (like
print_result()
) for easier analysis and auditing.
-
Runner Configuration Not Taking Effect:
- Double-check for any hardcoded runner settings in Python scripts that might override your YAML file.
- Confirm you are editing and using the correct configuration file during your runs.
Systematic troubleshooting and good observability tooling will help you quickly isolate and resolve issues, keeping automation workflows reliable and efficient.
Conclusion
Throughout this blog post, we’ve taken a deep dive into the Nornir Runner—a powerful backend component that controls how tasks are executed across your network devices. Here's a quick recap of what we've learned:
- Runner Plugins like
threaded
andserial
define how tasks are dispatched—either in parallel or sequentially. - Core Components like the task dispatcher, result aggregator, and worker threads enable scalable automation through structured concurrency.
- We walked through YAML and Python-based runner configurations so you can tune performance based on your specific environment.
- Through Python examples, you saw exactly how to implement and test Nornir tasks using the configured runner.
- We covered best practices that help prevent overloading resources and ensure stable, predictable automation.
- And finally, we outlined common troubleshooting steps to resolve issues during execution quickly and confidently.
The Nornir Runner is your automation engine—whether you're gathering configuration data from 10 devices or pushing changes to thousands across environments. With careful configuration, good logging, and structured testing, it will help you scale and secure your network automation efforts without compromise.
Thanks for reading!
Whether you’re just getting started with Nornir or fine-tuning your automation workflows, we hope this guide helped demystify how the Runner works and why it matters.
🧠 Stay curious.
🛠️ Automate with confidence.
📈 Keep scaling.
Happy automating! 🚀