(dev-config-netmiko)=
# Deploying Device Configurations with Netmiko
_netlab_ can use the [netmiko](https://github.com/ktbyers/netmiko) library instead of Ansible playbooks to deploy device configurations. The *netmiko* configuration method opens an SSH session to the device, enters the configuration mode, and sends the rendered configuration snippets to the device line-by-line. It's much faster than an Ansible playbook, as it does not have to start a separate Ansible process (and a separate SSH session) for every configuration snippet.
This document describes how the *netmiko* configuration method works and which device settings you have to define to use it. The *netmiko* configuration method is currently available on these platforms:
{.table-wrap}
| Device | Device
settings | *netmiko*
device type | Default configuration method |
|--------|--------------------|------------------------|------------------------------|
| Arista EOS | `eos.yml` | `arista_eos` | Ansible |
| Cisco IOS/IOS XE[^IOS] | `ios.yml` | `cisco_ios` | Ansible |
| Cisco Nexus OS | `nxos.yml` | `cisco_nxos` | **netmiko** |
| Cisco IOS XR[^XR] | `xr.yml` | `cisco_xr` | **netmiko** |
[^IOS]: Including all devices using **ios** as their parent device: Cisco IOSv, IOSvL2, CSR 1000v, Catalyst 8000v, IOL, and IOL L2 image.
[^XR]: Including all devices using **xr** as their parent device: IOS XRv, IOS XRd, and Cisco 8000v.
```eval_rst
.. contents:: Table of Contents
:depth: 2
:local:
:backlinks: none
```
## Selecting the Configuration Method
The configuration method used by a lab device is specified in the **netlab_config_mode** device group variable or node parameter. _netlab_ uses *netmiko* to configure a node when the value of that variable is `netmiko`.
The **netlab_config_mode** value must be one of the values listed in the **features.initial.config_mode** device feature. That list could be provider-specific. For example, Cisco IOS devices can use the *netmiko* configuration method with any virtualization provider, and the *startup* configuration method with *containerlab*:
```
features:
initial:
config_mode: [ netmiko ]
...
clab:
features:
initial:
config_mode: [ startup, netmiko ]
```
To make *netmiko* the default configuration method for a device, set the **group_vars.netlab_config_mode** device parameter. For example, Cisco Nexus OS uses this definition in the `nxos.yml` device settings file:
```
group_vars:
netlab_config_mode: netmiko
```
On devices where *netmiko* is supported but not the default configuration method (Arista EOS, Cisco IOS), the users can:
* Set the **netlab_config_mode** node parameter to `netmiko`
* Set the **defaults.devices._device_.group_vars.netlab_config_mode** (or the provider-specific **defaults.devices._device_._provider_.group_vars.netlab_config_mode**) [topology default](topo-defaults) to `netmiko`
* Use the **netlab install netmiko** command to install the *netmiko* library and set the **netlab_config_mode** in the [user defaults](defaults-user-file) of all devices that list `netmiko` in their **features.initial.config_mode** device feature.
```{tip}
The *libvirt* provider supports only the configuration methods specified in the **defaults.providers.libvirt.config_mode** list (`netmiko`, `sh`, and `cp_sh`).
```
## Device Settings
The *netmiko* configuration method uses the following device features (specified in the **features.netmiko** dictionary in the device settings):
{.table-wrap}
| Feature | Type | Meaning |
|---------|------|---------|
| **device_type** | string | *netmiko* device type (mandatory). See [netmiko documentation](https://github.com/ktbyers/netmiko/blob/develop/PLATFORMS.md) for the list of supported values |
| **error_regexp** | string or list | Regular expression(s) used to detect errors in the device responses to configuration commands. A list of regular expressions is combined into a single regular expression matching any of them |
| **delay** | int | Delay (in seconds) between establishing the SSH session and sending the first configuration snippet |
| **step_config** | bool | Exit the configuration mode after every configuration snippet |
These are the *netmiko* features used by the devices supporting the *netmiko* configuration method:
**Arista EOS** (`eos.yml`):
```
netmiko:
device_type: arista_eos
error_regexp: "^%.*"
```
**Cisco IOS** (`ios.yml`):
```
netmiko:
device_type: cisco_ios
error_regexp:
- (?i:invalid|incomplete|ambiguous|error|overlap|enabled|bad).*
```
**Cisco Nexus OS** (`nxos.yml`):
```
netmiko:
device_type: cisco_nxos
error_regexp: [ "^%(?!INFO).*", "(?i:invalid|error).*" ]
```
**Cisco IOS XR** (`xr.yml`):
```
netmiko:
device_type: cisco_xr
delay: 2 # Wait two seconds before trying to configure the device
error_regexp: "^%.*"
step_config: True
```
```{tip}
The **error_regexp** regular expression should match the whole error message, not just its first few characters. The matched text is included in the error message _netlab_ displays when the configuration deployment fails.
```
The *netmiko* connection parameters are derived from these Ansible group variables (they could be set as device **group_vars** or as node parameters):
| Ansible variable | *netmiko* parameter | Mandatory |
|------------------|---------------------|:---------:|
| **ansible_user** | **username** | ✅ |
| **ansible_ssh_pass** | **password** | ✅ |
| **ansible_become_password** | **secret** (used by the **enable** command) | ❌ |
The SSH session is established with the node's management IPv4 address (**mgmt.ipv4**) or IPv6 address (**mgmt.ipv6**) when the node has no IPv4 management address. _netlab_ cannot use *netmiko* to configure nodes without a management IP address.
## Creating the Configuration Snippets
When the **netlab_config_mode** is set, the provider modules (*clab* and *libvirt*) add all configuration snippets used by the node (**normalize** when the device has the **features.initial.normalize** feature, **initial**, all modules specified in the node **module** list, and all custom configuration templates specified in the node **config** list) to the internal **_node_config** dictionary. The *netmiko* entries in that dictionary have the value `:netmiko` (they have no target file name).
The configuration snippets are also added to the **netlab_ansible_skip_module** list to prevent the Ansible playbook from deploying them a second time.
The **netlab initial** command renders the configuration templates into the `node_files/_nodename_` directory using the [regular configuration template search process](dev-config-deploy-paths) (the platform name used in template file names is the value of the **netlab_device_type** or **ansible_network_os** variable). The rendered files have no suffix; for example, the initial device configuration of node *r1* is in `node_files/r1/initial`.
You can use the same configuration templates for Ansible and *netmiko* configuration methods. The configuration templates contain configuration commands that are sent to the device in configuration mode, and you can use the device configuration mode commands (for example, **do** commands on Arista EOS) in them.
If you need a configuration method-specific configuration command, use the **netlab_config_mode** variable in the configuration template. For example, the Arista EOS **normalize** template disables interface PHY emulation when the configuration is deployed with *netmiko*:
```jinja
{% for intf in interfaces if intf.virtual_interface is not defined %}
!
interface {{ intf.ifname }}
{% if netlab_config_mode in ['netmiko','sh'] %}
platform tfa phy control-frame disabled
{% endif %}
{% endfor %}
```
## Deploying the Configuration Snippets
The configuration deployment process is implemented in the **netsim.cli.initial.netmiko** module (using utility functions from **netsim.utils.netmiko** module) and is executed as part of the **netlab initial** command (which is also called as the last step of **netlab up**):
* **netlab initial** waits for the devices to become ready (see [](dev-config-deploy-paths)), and then starts a separate configuration deployment thread for every node.
* Nodes with the **netlab_config_mode** set to `netmiko` are configured with the *netmiko* library. All other configuration snippets (or nodes) are configured afterwards with the **netlab initial** Ansible playbook.
* If a device needs the *normalize* step, the **normalize** configuration snippet is deployed in a separate run before the **initial** configuration snippet is deployed.
_netlab_ uses this procedure to deploy configuration snippets with *netmiko*:
* Opens an SSH session to the device using **netmiko.ConnectHandler** and executes the **enable** command (using **ansible_become_password** as the *enable secret*)
* Waits for the **features.netmiko.delay** seconds (when specified)
* Executes the **send_config_from_file** function for every configuration snippet, using the **features.netmiko.error_regexp** regular expression to detect configuration errors.
* Executes the **commit** command when the *netmiko* device driver supports it (for example, on Cisco IOS XR)
* Exits the configuration mode when the **features.netmiko.step_config** device feature is set.
* Resets the base prompt after the **normalize** or **initial** configuration (the initial device configuration usually changes the device hostname)
The configuration deployment stops on the first configuration error, and the remaining configuration snippets are not deployed. _netlab_ displays the error message (including the text matched by the **error_regexp** expression) and the name of the session log file.
After the configuration deployment threads (and the Ansible playbook) complete, **netlab initial** displays the summary of *netmiko*-deployed configuration snippets.
### Deploying Custom Configuration Templates
The **netlab config** command uses the same deployment process for custom configuration templates when the node uses the *netmiko* configuration method. The **netlab config --reload** command always uses the Ansible playbook to reload the saved device configurations.
## Troubleshooting
* *netmiko* writes the log of all SSH session interactions to `node_files/_nodename_/netmiko.log`
* Use the **netlab initial --debug netmiko** command to display the *netmiko* connection parameters, the error-detection regular expression, and the device responses to the configuration commands
* Use the **netlab initial -o** command to create the configuration snippets in the `config` directory without deploying them
* Use the **netlab initial --dry-run** command to display the configuration snippets that would be deployed
## Tests
You can use any integration test (see [](dev-config-initial-tests)) to test the *netmiko* configuration method. To use the *netmiko* configuration method on a device that uses a different configuration method by default, set the **netlab_config_mode** device group variable with a CLI parameter; for example:
```
netlab up -d eos -s defaults.devices.eos.group_vars.netlab_config_mode=netmiko
```
The `tests/config` directory contains topologies that can be used to test the error detection on Cisco IOS (`ios-netmiko.yml`) and Nexus OS (`nxos-netmiko.yml`) with the **netlab config** command. For example, to verify that the *netmiko* configuration method detects invalid configuration commands on Cisco IOS:
* Start the lab with `netlab up ios-netmiko.yml`
* Execute `netlab config invalid` to deploy an invalid configuration command; the configuration deployment should fail.