Merge pull request #48260 from mirceaulinic/netmiko-proxy

Adding the initial version of the Netmiko Proxy and Execution modules
This commit is contained in:
Nicole Thomas 2018-06-25 10:02:28 -04:00 committed by GitHub
commit 210d558615
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 1000 additions and 0 deletions

View File

@ -283,6 +283,7 @@ execution modules
netbox
netbsd_sysctl
netbsdservice
netmiko_mod
netscaler
network
neutron

View File

@ -0,0 +1,7 @@
========================
salt.modules.netmiko_mod
========================
.. automodule:: salt.modules.netmiko_mod
:members:

View File

@ -20,6 +20,7 @@ proxy modules
junos
marathon
napalm
netmiko_px
nxos
panos
philips_hue

View File

@ -0,0 +1,6 @@
==================
salt.proxy.netmiko
==================
.. automodule:: salt.proxy.netmiko_px
:members:

645
salt/modules/netmiko_mod.py Normal file
View File

@ -0,0 +1,645 @@
# -*- coding: utf-8 -*-
'''
Netmiko Execution Module
========================
.. versionadded:: Fluorine
Execution module to interface the connection with a remote network device. It is
flexible enough to execute the commands both when running under a Netmiko Proxy
Minion, as well as running under a Regular Minion by specifying the connection
arguments, i.e., ``device_type``, ``ip``, ``username``, ``password`` etc.
:codeauthor: Mircea Ulinic <ping@mirceaulinic.net> & Kirk Byers <ktbyers@twb-tech.com>
:maturity: new
:depends: netmiko
:platform: unix
Dependencies
------------
The ``netmiko`` proxy modules requires Netmiko to be installed: ``pip install netmiko``.
Usage
-----
This module can equally be used via the :mod:`netmiko <salt.proxy.netmiko_px>`
Proxy module (check documentation), or directly from an arbitrary (Proxy) Minion
that is running on a server (computer) having access to the network device, and
has the ``netmiko`` library installed.
When running outside of the :mod:`netmiko Proxy <salt.proxy.netmiko_px>` (i.e.,
from another Proxy Minion type, or regular Minion), the netmiko connection
arguments can be either specified from the CLI when executing the command, or
in a configuration block under the ``netmiko`` key in the configuration opts
(i.e., (Proxy) Minion configuration file), or Pillar. The module supports these
simultaneously. These fields are the exact same supported by the ``netmiko``
Proxy Module:
device_type
Class selection based on device type. Supported options:
- ``a10``: A10 Networks
- ``accedian``: Accedian Networks
- ``alcatel_aos``: Alcatel AOS
- ``alcatel_sros``: Alcatel SROS
- ``apresia_aeos``: Apresia AEOS
- ``arista_eos``: Arista EOS
- ``aruba_os``: Aruba
- ``avaya_ers``: Avaya ERS
- ``avaya_vsp``: Avaya VSP
- ``brocade_fastiron``: Brocade Fastiron
- ``brocade_netiron``: Brocade Netiron
- ``brocade_nos``: Brocade NOS
- ``brocade_vdx``: Brocade NOS
- ``brocade_vyos``: VyOS
- ``checkpoint_gaia``: Check Point GAiA
- ``calix_b6``: Calix B6
- ``ciena_saos``: Ciena SAOS
- ``cisco_asa``: Cisco SA
- ``cisco_ios``: Cisco IOS
- ``cisco_nxos``: Cisco NX-oS
- ``cisco_s300``: Cisco S300
- ``cisco_tp``: Cisco TpTcCe
- ``cisco_wlc``: Cisco WLC
- ``cisco_xe``: Cisco IOS
- ``cisco_xr``: Cisco XR
- ``coriant``: Coriant
- ``dell_force10``: Dell Force10
- ``dell_os10``: Dell OS10
- ``dell_powerconnect``: Dell PowerConnect
- ``eltex``: Eltex
- ``enterasys``: Enterasys
- ``extreme``: Extreme
- ``extreme_wing``: Extreme Wing
- ``f5_ltm``: F5 LTM
- ``fortinet``: Fortinet
- ``generic_termserver``: TerminalServer
- ``hp_comware``: HP Comware
- ``hp_procurve``: HP Procurve
- ``huawei``: Huawei
- ``huawei_vrpv8``: Huawei VRPV8
- ``juniper``: Juniper Junos
- ``juniper_junos``: Juniper Junos
- ``linux``: Linux
- ``mellanox``: Mellanox
- ``mrv_optiswitch``: MrvOptiswitch
- ``netapp_cdot``: NetAppcDot
- ``netscaler``: Netscaler
- ``ovs_linux``: OvsLinux
- ``paloalto_panos``: PaloAlto Panos
- ``pluribus``: Pluribus
- ``quanta_mesh``: Quanta Mesh
- ``ruckus_fastiron``: Ruckus Fastiron
- ``ubiquiti_edge``: Ubiquiti Edge
- ``ubiquiti_edgeswitch``: Ubiquiti Edge
- ``vyatta_vyos``: VyOS
- ``vyos``: VyOS
- ``brocade_fastiron_telnet``: Brocade Fastiron over Telnet
- ``brocade_netiron_telnet``: Brocade Netiron over Telnet
- ``cisco_ios_telnet``: Cisco IOS over Telnet
- ``apresia_aeos_telnet``: Apresia AEOS over Telnet
- ``arista_eos_telnet``: Arista EOS over Telnet
- ``hp_procurve_telnet``: HP Procurve over Telnet
- ``hp_comware_telnet``: HP Comware over Telnet
- ``juniper_junos_telnet``: Juniper Junos over Telnet
- ``calix_b6_telnet``: Calix B6 over Telnet
- ``dell_powerconnect_telnet``: Dell PowerConnect over Telnet
- ``generic_termserver_telnet``: TerminalServer over Telnet
- ``extreme_telnet``: Extreme Networks over Telnet
- ``ruckus_fastiron_telnet``: Ruckus Fastiron over Telnet
- ``cisco_ios_serial``: Cisco IOS over serial port
ip
IP address of target device. Not required if ``host`` is provided.
host
Hostname of target device. Not required if ``ip`` is provided.
username
Username to authenticate against target device if required.
password
Password to authenticate against target device if required.
secret
The enable password if target device requires one.
port
The destination port used to connect to the target device.
global_delay_factor: ``1``
Multiplication factor affecting Netmiko delays (default: ``1``).
use_keys: ``False``
Connect to target device using SSH keys.
key_file
Filename path of the SSH key file to use.
allow_agent
Enable use of SSH key-agent.
ssh_strict: ``False``
Automatically reject unknown SSH host keys (default: ``False``, which means
unknown SSH host keys will be accepted).
system_host_keys: ``False``
Load host keys from the user's 'known_hosts' file.
alt_host_keys: ``False``
If ``True`` host keys will be loaded from the file specified in
``alt_key_file``.
alt_key_file
SSH host key file to use (if ``alt_host_keys=True``).
ssh_config_file
File name of OpenSSH configuration file.
timeout: ``90``
Connection timeout (in seconds).
session_timeout: ``60``
Set a timeout for parallel requests (in seconds).
keepalive: ``0``
Send SSH keepalive packets at a specific interval, in seconds. Currently
defaults to ``0``, for backwards compatibility (it will not attempt to keep
the connection alive using the KEEPALIVE packets).
default_enter: ``\n``
Character(s) to send to correspond to enter key (default: ``\n``).
response_return: ``\n``
Character(s) to use in normalized return data to represent enter key
(default: ``\n``)
Example (when not running in a ``netmiko`` Proxy Minion):
.. code-block:: yaml
netmiko:
username: test
password: test
In case the ``username`` and ``password`` are the same on any device you are
targeting, the block above (besides other parameters specific to your
environment you might need) should suffice to be able to execute commands from
outside a ``netmiko`` Proxy, e.g.:
.. code-block:: bash
salt '*' netmiko.send_command 'show version' host=router1.example.com device_type=juniper
salt '*' netmiko.send_config https://bit.ly/2sgljCB host=sw2.example.com device_type=cisco_ios
.. note::
Remember that the above applies only when not running in a ``netmiko`` Proxy
Minion. If you want to use the :mod:`<salt.proxy.netmiko_px>`, please follow
the documentation notes for a proper setup.
'''
from __future__ import absolute_import
# Import python stdlib
import logging
import inspect
# Import Salt libs
from salt.ext import six
from salt.exceptions import CommandExecutionError
try:
from salt.utils.args import clean_kwargs
from salt.utils.files import mkstemp
except ImportError:
from salt.utils import clean_kwargs
from salt.utils import mkstemp
# Import third party libs
try:
from netmiko import ConnectHandler
from netmiko import BaseConnection
HAS_NETMIKO = True
except ImportError:
HAS_NETMIKO = False
# -----------------------------------------------------------------------------
# execution module properties
# -----------------------------------------------------------------------------
__proxyenabled__ = ['*']
# Any Proxy Minion should be able to execute these (not only netmiko)
__virtualname__ = 'netmiko'
# The Execution Module will be identified as ``netmiko``
# -----------------------------------------------------------------------------
# globals
# -----------------------------------------------------------------------------
log = logging.getLogger(__name__)
# -----------------------------------------------------------------------------
# propery functions
# -----------------------------------------------------------------------------
def __virtual__():
'''
Execution module available only if Netmiko is installed.
'''
if not HAS_NETMIKO:
return False, 'The netmiko execution module requires netmiko library to be installed.'
return __virtualname__
# -----------------------------------------------------------------------------
# helper functions
# -----------------------------------------------------------------------------
def _prepare_connection(**kwargs):
'''
Prepare the connection with the remote network device, and clean up the key
value pairs, removing the args used for the connection init.
'''
init_args = {}
fun_kwargs = {}
netmiko_kwargs = __salt__['config.get']('netmiko', {})
netmiko_kwargs.update(kwargs) # merge the CLI args with the opts/pillar
netmiko_init_args, _, _, netmiko_defaults = inspect.getargspec(BaseConnection.__init__)
check_self = netmiko_init_args.pop(0)
for karg, warg in six.iteritems(netmiko_kwargs):
if karg not in netmiko_init_args:
if warg is not None:
fun_kwargs[karg] = warg
continue
if warg is not None:
init_args[karg] = warg
conn = ConnectHandler(**init_args)
return conn, fun_kwargs
# -----------------------------------------------------------------------------
# callable functions
# -----------------------------------------------------------------------------
def get_connection(**kwargs):
'''
Return the Netmiko connection object.
.. warning::
This function returns an unserializable object, hence it is not meant
to be used on the CLI. This should mainly be used when invoked from
other modules for the low level connection with the network device.
kwargs
Key-value dictionary with the authentication details.
USAGE Example:
.. code-block:: python
conn = __salt__['netmiko.get_connection'](host='router1.example.com',
username='example',
password='example')
show_if = conn.send_command('show interfaces')
conn.disconnect()
'''
kwargs = clean_kwargs(**kwargs)
if 'netmiko.conn' in __proxy__:
return __proxy__['netmiko.conn']()
conn, kwargs = _prepare_connection(**kwargs)
return conn
def call(method, *args, **kwargs):
'''
Invoke an arbitrary Netmiko method.
method
The name of the Netmiko method to invoke.
args
A list of arguments to send to the method invoked.
kwargs
Key-value dictionary to send to the method invoked.
'''
kwargs = clean_kwargs(**kwargs)
if 'netmiko.call' in __proxy__:
return __proxy__['netmiko.call'](method, *args, **kwargs)
conn, kwargs = _prepare_connection(**kwargs)
ret = getattr(conn, method)(*args, **kwargs)
conn.disconnect()
return ret
def multi_call(*methods, **kwargs):
'''
Invoke multiple Netmiko methods at once, and return their output, as list.
methods
A list of dictionaries with the following keys:
- ``name``: the name of the Netmiko method to be executed.
- ``args``: list of arguments to be sent to the Netmiko method.
- ``kwargs``: dictionary of arguments to be sent to the Netmiko method.
kwargs
Key-value dictionary with the connection details (when not running
under a Proxy Minion).
'''
kwargs = clean_kwargs(**kwargs)
if 'netmiko.conn' in __proxy__:
conn = __proxy__['netmiko.conn']()
else:
conn, kwargs = _prepare_connection(**kwargs)
ret = []
for method in methods:
# Explicit unpacking
method_name = method['name']
method_args = method.get('args', [])
method_kwargs = method.get('kwargs', [])
ret.append(getattr(conn, method_name)(*method_args, **method_kwargs))
if 'netmiko.conn' not in __proxy__:
conn.disconnect()
return ret
def send_command(command_string, **kwargs):
'''
Execute command_string on the SSH channel using a pattern-based mechanism.
Generally used for show commands. By default this method will keep waiting
to receive data until the network device prompt is detected. The current
network device prompt will be determined automatically.
command_string
The command to be executed on the remote device.
expect_string
Regular expression pattern to use for determining end of output.
If left blank will default to being based on router prompt.
delay_factor: ``1``
Multiplying factor used to adjust delays (default: ``1``).
max_loops: ``500``
Controls wait time in conjunction with delay_factor. Will default to be
based upon self.timeout.
auto_find_prompt: ``True``
Whether it should try to auto-detect the prompt (default: ``True``).
strip_prompt: ``True``
Remove the trailing router prompt from the output (default: ``True``).
strip_command: ``True``
Remove the echo of the command from the output (default: ``True``).
normalize: ``True``
Ensure the proper enter is sent at end of command (default: ``True``).
use_textfsm: ``False``
Process command output through TextFSM template (default: ``False``).
CLI Example:
.. code-block:: bash
salt '*' netmiko.send_command 'show version'
salt '*' netmiko.send_command 'show_version' host='router1.example.com' username='example' device_type='cisco_ios'
'''
return call('send_command', command_string, **kwargs)
def send_command_timing(command_string, **kwargs):
'''
Execute command_string on the SSH channel using a delay-based mechanism.
Generally used for show commands.
command_string
The command to be executed on the remote device.
delay_factor: ``1``
Multiplying factor used to adjust delays (default: ``1``).
max_loops: ``500``
Controls wait time in conjunction with delay_factor. Will default to be
based upon self.timeout.
strip_prompt: ``True``
Remove the trailing router prompt from the output (default: ``True``).
strip_command: ``True``
Remove the echo of the command from the output (default: ``True``).
normalize: ``True``
Ensure the proper enter is sent at end of command (default: ``True``).
use_textfsm: ``False``
Process command output through TextFSM template (default: ``False``).
CLI Example:
.. code-block:: bash
salt '*' netmiko.send_command_timing 'show version'
salt '*' netmiko.send_command_timing 'show version' host='router1.example.com' username='example' device_type='arista_eos'
'''
return call('send_command_timing', command_string, **kwargs)
def enter_config_mode(**kwargs):
'''
Enter into config mode.
config_command
Configuration command to send to the device.
pattern
Pattern to terminate reading of channel.
CLI Example:
.. code-block:: bash
salt '*' netmiko.enter_config_mode
salt '*' netmiko.enter_config_mode device_type='juniper_junos' ip='192.168.0.1' username='example'
'''
return call('config_mode', **kwargs)
def exit_config_mode(**kwargs):
'''
Exit from configuration mode.
exit_config
Command to exit configuration mode.
pattern
Pattern to terminate reading of channel.
CLI Example:
.. code-block:: bash
salt '*' netmiko.exit_config_mode
salt '*' netmiko.exit_config_mode device_type='juniper' ip='192.168.0.1' username='example'
'''
return call('exit_config_mode', **kwargs)
def send_config(config_file=None,
config_commands=None,
template_engine='jinja',
source_hash=None,
source_hash_name=None,
user=None,
group=None,
mode=None,
attrs=None,
context=None,
defaults=None,
skip_verify=False,
saltenv='base',
**kwargs):
'''
Send configuration commands down the SSH channel.
Return the configuration lines sent to the device.
The function is flexible to send the configuration from a local or remote
file, or simply the commands as list.
config_file
The source file with the configuration commands to be sent to the
device.
The file can also be a template that can be rendered using the template
engine of choice.
This can be specified using the absolute path to the file, or using one
of the following URL schemes:
- ``salt://``, to fetch the file from the Salt fileserver.
- ``http://`` or ``https://``
- ``ftp://``
- ``s3://``
- ``swift://``
config_commands
Multiple configuration commands to be sent to the device.
.. note::
This argument is ignored when ``config_file`` is specified.
template_engine: ``jinja``
The template engine to use when rendering the source file. Default:
``jinja``. To simply fetch the file without attempting to render, set
this argument to ``None``.
source_hash
The hash of the ``config_file``
source_hash_name
When ``source_hash`` refers to a remote file, this specifies the
filename to look for in that file.
user
Owner of the file.
group
Group owner of the file.
mode
Permissions of the file.
attrs
Attributes of the file.
context
Variables to add to the template context.
defaults
Default values of the context_dict.
skip_verify: ``False``
If ``True``, hash verification of remote file sources (``http://``,
``https://``, ``ftp://``, etc.) will be skipped, and the ``source_hash``
argument will be ignored.
exit_config_mode: ``True``
Determines whether or not to exit config mode after complete.
delay_factor: ``1``
Factor to adjust delays.
max_loops: ``150``
Controls wait time in conjunction with delay_factor (default: ``150``).
strip_prompt: ``False``
Determines whether or not to strip the prompt (default: ``False``).
strip_command: ``False``
Determines whether or not to strip the command (default: ``False``).
config_mode_command
The command to enter into config mode.
CLI Example:
.. code-block:: bash
salt '*' netmiko.send_config config_file=salt://config.txt
salt '*' netmiko.send_config config_file=https://bit.ly/2sgljCB device_type='cisco_ios' ip='1.2.3.4' username='example'
'''
if config_file:
if template_engine:
tmp_file = mkstemp()
file_mgd = __salt__['file.get_managed'](tmp_file,
template_engine,
config_file,
source_hash,
source_hash_name,
user,
group,
mode,
attrs,
saltenv,
context,
defaults,
skip_verify)
if not file_mgd[0]:
raise CommandExecutionError(file_mgd[2])
file_str = __salt__['file.read'](file_mgd[0])
__salt__['file.remove'](file_mgd[0])
else:
# If no template engine wanted, simply fetch the source file
file_str = __salt__['cp.get_file_str'](config_file,
saltenv=saltenv)
if file_str is False:
raise CommandExecutionError('Source file {} not found'.format(config_file))
config_commands = file_str.splitlines()
if isinstance(config_commands, (six.string_types, six.text_type)):
config_commands = [config_commands]
call('send_config_set', config_commands=config_commands, **kwargs)
return config_commands
def commit(**kwargs):
'''
Commit the configuration changes.
.. warning::
This function is supported only on the platforms that support the
``commit`` operation.
CLI Example:
.. code-block:: bash
salt '*' netmiko.commit
'''
return call('commit', **kwargs)

340
salt/proxy/netmiko_px.py Normal file
View File

@ -0,0 +1,340 @@
# -*- coding: utf-8 -*-
'''
Netmiko
=======
.. versionadded:: Fluorine
Proxy module for managing network devices via
`Netmiko <https://github.com/ktbyers/netmiko>`_.
:codeauthor: Mircea Ulinic <ping@mirceaulinic.net> & Kirk Byers <ktbyers@twb-tech.com>
:maturity: new
:depends: netmiko
:platform: unix
Dependencies
------------
The ``netmiko`` proxy modules requires Netmiko to be installed: ``pip install netmiko``.
Pillar
------
The ``netmiko`` proxy configuration requires the following parameters in order
to connect to the network device:
device_type
Class selection based on device type. Supported options:
- ``a10``: A10 Networks
- ``accedian``: Accedian Networks
- ``alcatel_aos``: Alcatel AOS
- ``alcatel_sros``: Alcatel SROS
- ``apresia_aeos``: Apresia AEOS
- ``arista_eos``: Arista EOS
- ``aruba_os``: Aruba
- ``avaya_ers``: Avaya ERS
- ``avaya_vsp``: Avaya VSP
- ``brocade_fastiron``: Brocade Fastiron
- ``brocade_netiron``: Brocade Netiron
- ``brocade_nos``: Brocade NOS
- ``brocade_vdx``: Brocade NOS
- ``brocade_vyos``: VyOS
- ``checkpoint_gaia``: Check Point GAiA
- ``calix_b6``: Calix B6
- ``ciena_saos``: Ciena SAOS
- ``cisco_asa``: Cisco SA
- ``cisco_ios``: Cisco IOS
- ``cisco_nxos``: Cisco NX-oS
- ``cisco_s300``: Cisco S300
- ``cisco_tp``: Cisco TpTcCe
- ``cisco_wlc``: Cisco WLC
- ``cisco_xe``: Cisco IOS
- ``cisco_xr``: Cisco XR
- ``coriant``: Coriant
- ``dell_force10``: Dell Force10
- ``dell_os10``: Dell OS10
- ``dell_powerconnect``: Dell PowerConnect
- ``eltex``: Eltex
- ``enterasys``: Enterasys
- ``extreme``: Extreme
- ``extreme_wing``: Extreme Wing
- ``f5_ltm``: F5 LTM
- ``fortinet``: Fortinet
- ``generic_termserver``: TerminalServer
- ``hp_comware``: HP Comware
- ``hp_procurve``: HP Procurve
- ``huawei``: Huawei
- ``huawei_vrpv8``: Huawei VRPV8
- ``juniper``: Juniper Junos
- ``juniper_junos``: Juniper Junos
- ``linux``: Linux
- ``mellanox``: Mellanox
- ``mrv_optiswitch``: MrvOptiswitch
- ``netapp_cdot``: NetAppcDot
- ``netscaler``: Netscaler
- ``ovs_linux``: OvsLinux
- ``paloalto_panos``: PaloAlto Panos
- ``pluribus``: Pluribus
- ``quanta_mesh``: Quanta Mesh
- ``ruckus_fastiron``: Ruckus Fastiron
- ``ubiquiti_edge``: Ubiquiti Edge
- ``ubiquiti_edgeswitch``: Ubiquiti Edge
- ``vyatta_vyos``: VyOS
- ``vyos``: VyOS
- ``brocade_fastiron_telnet``: Brocade Fastiron over Telnet
- ``brocade_netiron_telnet``: Brocade Netiron over Telnet
- ``cisco_ios_telnet``: Cisco IOS over Telnet
- ``apresia_aeos_telnet``: Apresia AEOS over Telnet
- ``arista_eos_telnet``: Arista EOS over Telnet
- ``hp_procurve_telnet``: HP Procurve over Telnet
- ``hp_comware_telnet``: HP Comware over Telnet
- ``juniper_junos_telnet``: Juniper Junos over Telnet
- ``calix_b6_telnet``: Calix B6 over Telnet
- ``dell_powerconnect_telnet``: Dell PowerConnect over Telnet
- ``generic_termserver_telnet``: TerminalServer over Telnet
- ``extreme_telnet``: Extreme Networks over Telnet
- ``ruckus_fastiron_telnet``: Ruckus Fastiron over Telnet
- ``cisco_ios_serial``: Cisco IOS over serial port
ip
IP address of target device. Not required if ``host`` is provided.
host
Hostname of target device. Not required if ``ip`` is provided.
username
Username to authenticate against target device if required.
password
Password to authenticate against target device if required.
secret
The enable password if target device requires one.
port
The destination port used to connect to the target device.
global_delay_factor: ``1``
Multiplication factor affecting Netmiko delays (default: ``1``).
use_keys: ``False``
Connect to target device using SSH keys.
key_file
Filename path of the SSH key file to use.
allow_agent
Enable use of SSH key-agent.
ssh_strict: ``False``
Automatically reject unknown SSH host keys (default: ``False``, which means
unknown SSH host keys will be accepted).
system_host_keys: ``False``
Load host keys from the user's 'known_hosts' file.
alt_host_keys: ``False``
If ``True`` host keys will be loaded from the file specified in
``alt_key_file``.
alt_key_file
SSH host key file to use (if ``alt_host_keys=True``).
ssh_config_file
File name of OpenSSH configuration file.
timeout: ``90``
Connection timeout (in seconds).
session_timeout: ``60``
Set a timeout for parallel requests (in seconds).
keepalive: ``0``
Send SSH keepalive packets at a specific interval, in seconds. Currently
defaults to ``0``, for backwards compatibility (it will not attempt to keep
the connection alive using the KEEPALIVE packets).
default_enter: ``\n``
Character(s) to send to correspond to enter key (default: ``\n``).
response_return: ``\n``
Character(s) to use in normalized return data to represent enter key
(default: ``\n``)
always_alive: ``True``
In certain less dynamic environments, maintaining the remote connection
permanently open with the network device is not always beneficial. In that
case, the user can select to initialize the connection only when needed, by
specifying this field to ``false``.
Default: ``true`` (maintains the connection with the remote network device).
multiprocessing: ``False``
Overrides the :conf_minion:`multiprocessing` option, per proxy minion, as
the Netmiko communication channel is mainly SSH.
Proxy Pillar Example
--------------------
.. code-block:: yaml
proxy:
proxytype: netmiko
device_type: juniper_junos
host: router1.example.com
username: example
password: example
.. code-block:: yaml
proxy:
proxytype: netmiko
device_type: cisco_ios
ip: 1.2.3.4
username: test
use_keys: true
secret: w3@k
'''
from __future__ import absolute_import
# Import python stdlib
import logging
# Import third party libs
try:
from netmiko import ConnectHandler
from netmiko.ssh_exception import NetMikoTimeoutException
from netmiko.ssh_exception import NetMikoAuthenticationException
HAS_NETMIKO = True
except ImportError:
HAS_NETMIKO = False
# Import salt modules
try:
from salt.utils.args import clean_kwargs
except ImportError:
from salt.utils import clean_kwargs
# -----------------------------------------------------------------------------
# proxy properties
# -----------------------------------------------------------------------------
__proxyenabled__ = ['netmiko']
# proxy name
# -----------------------------------------------------------------------------
# globals
# -----------------------------------------------------------------------------
__virtualname__ = 'netmiko'
log = logging.getLogger(__name__)
netmiko_device = {}
# -----------------------------------------------------------------------------
# propery functions
# -----------------------------------------------------------------------------
def __virtual__():
'''
Proxy module available only if Netmiko is installed.
'''
if not HAS_NETMIKO:
return False, 'The netmiko proxy module requires netmiko library to be installed.'
return __virtualname__
# -----------------------------------------------------------------------------
# proxy functions
# -----------------------------------------------------------------------------
def init(opts):
'''
Open the connection to the network device
managed through netmiko.
'''
proxy_dict = opts.get('proxy', {})
opts['multiprocessing'] = proxy_dict.get('multiprocessing', False)
netmiko_connection_args = proxy_dict.copy()
netmiko_connection_args.pop('proxytype', None)
netmiko_device['always_alive'] = netmiko_connection_args.pop('always_alive',
opts.get('proxy_always_alive', True))
try:
connection = ConnectHandler(**netmiko_connection_args)
netmiko_device['connection'] = connection
netmiko_device['initialized'] = True
netmiko_device['args'] = netmiko_connection_args
netmiko_device['up'] = True
if not netmiko_device['always_alive']:
netmiko_device['connection'].disconnect()
except NetMikoTimeoutException as t_err:
log.error('Unable to setup the netmiko connection', exc_info=True)
except NetMikoAuthenticationException as au_err:
log.error('Unable to setup the netmiko connection', exc_info=True)
return True
def alive(opts):
'''
Return the connection status with the network device.
'''
log.debug('Checking if %s is still alive', opts.get('id', ''))
if not netmiko_device['always_alive']:
return True
if ping() and initialized():
return netmiko_device['connection'].remote_conn.transport.is_alive()
return False
def ping():
'''
Connection open successfully?
'''
return netmiko_device.get('up', False)
def initialized():
'''
Connection finished initializing?
'''
return netmiko_device.get('initialized', False)
def shutdown(opts):
'''
Closes connection with the device.
'''
return call('disconnect')
# -----------------------------------------------------------------------------
# callable functions
# -----------------------------------------------------------------------------
def conn():
'''
Return the connection object.
'''
return netmiko_device.get('connection')
def args():
'''
Return the Netmiko device args.
'''
return netmiko_device['args']
def call(method, *args, **kwargs):
'''
Calls an arbitrary netmiko method.
'''
kwargs = clean_kwargs(**kwargs)
if not netmiko_device['always_alive']:
connection = ConnectHandler(**netmiko_device['args'])
ret = getattr(connection, method)(*args, **kwargs)
connection.disconnect()
return ret
return getattr(netmiko_device['connection'], method)(*args, **kwargs)