Skip to content

Commit

Permalink
Merge pull request #31431 from jejenone/napalm_proxy_minion
Browse files Browse the repository at this point in the history
Napalm library based proxy minion
  • Loading branch information
Mike Place committed Feb 23, 2016
2 parents abb4539 + 8ad5794 commit 437b983
Show file tree
Hide file tree
Showing 6 changed files with 501 additions and 0 deletions.
1 change: 1 addition & 0 deletions doc/ref/modules/all/index.rst
Expand Up @@ -198,6 +198,7 @@ Full list of builtin execution modules
nacl
nagios
nagios_rpc
napalm_network
netaddress
netbsd_sysctl
netbsdservice
Expand Down
6 changes: 6 additions & 0 deletions doc/ref/modules/all/salt.modules.napalm_network.rst
@@ -0,0 +1,6 @@
salt.modules.napalm_network module
===============================

.. automodule:: salt.modules.napalm_network
:members:
:undoc-members:
1 change: 1 addition & 0 deletions doc/ref/proxy/all/index.rst
Expand Up @@ -15,6 +15,7 @@ Full list of builtin proxy modules
fx2
junos
marathon
napalm
phillips_hue
rest_sample
ssh_sample
6 changes: 6 additions & 0 deletions doc/ref/proxy/all/salt.proxy.napalm.rst
@@ -0,0 +1,6 @@
================
salt.proxy.napalm
================

.. automodule:: salt.proxy.napalm
:members:
316 changes: 316 additions & 0 deletions salt/modules/napalm_network.py
@@ -0,0 +1,316 @@
# -*- coding: utf-8 -*-
'''
Basic functions from Napalm library
'''

from __future__ import absolute_import

import logging
log = logging.getLogger(__name__)

# ------------------------------------------------------------------------
# module properties
# ------------------------------------------------------------------------

__virtualname__ = 'net'
__proxyenabled__ = ['napalm']
# uses NAPALM-based proxy to interact with network devices

# ------------------------------------------------------------------------
# property functions
# ------------------------------------------------------------------------


def __virtual__():
return True

# ------------------------------------------------------------------------
# helper functions -- will not be exported
# ------------------------------------------------------------------------


def _filter_list(input_list, search_key, search_value):

output_list = list()

for dictionary in input_list:
if dictionary.get(search_key) == search_value:
output_list.append(dictionary)

return output_list


def _filter_dict(input_dict, search_key, search_value):

output_dict = dict()

for key, key_list in input_dict.iteritems():
key_list_filtered = _filter_list(key_list, search_key, search_value)
if key_list_filtered:
output_dict[key] = key_list_filtered

return output_dict

# ------------------------------------------------------------------------
# callable functions
# ------------------------------------------------------------------------


def ping():
'''
is the device alive ?
CLI example:
.. code-block:: bash
salt myminion net.ping
'''

return {
'out': __proxy__['napalm.ping']()
}


def cli(*commands):

"""
NAPALM returns a dictionary with the output of all commands passed as arguments:
CLI example:
.. code-block:: bash
salt myminion net.cli "show version" "show route 8.8.8.8"
:param commands: list of raw commands to execute on device
Example:
{
u'show version and haiku' : u'''Hostname: re0.edge01.arn01
Model: mx480
Junos: 13.3R6.5
Help me, Obi-Wan
I just saw Episode Two
You're my only hope
''',
u'show chassis fan' : u'''Item Status RPM Measurement
Top Rear Fan OK 3840 Spinning at intermediate-speed
Bottom Rear Fan OK 3840 Spinning at intermediate-speed
Top Middle Fan OK 3900 Spinning at intermediate-speed
Bottom Middle Fan OK 3840 Spinning at intermediate-speed
Top Front Fan OK 3810 Spinning at intermediate-speed
Bottom Front Fan OK 3840 Spinning at intermediate-speed
'''
}
"""

return __proxy__['napalm.call'](
'cli',
**{
'commands': list(commands)
}
)
# thus we can display the output as is
# in case of errors, they'll be catched in the proxy


def arp(interface='', ipaddr='', macaddr=''):

"""
NAPALM returns a list of dictionaries with details of the ARP entries:
[{INTERFACE, MAC, IP, AGE}]
CLI example:
.. code-block:: bash
salt myminion net.arp
salt myminion net.arp macaddr='5c:5e:ab:da:3c:f0'
:param interface: interface name to filter on
:param ipaddr: IP address to filter on
:param macaddr: MAC address to filter on
Example output:
[
{
'interface' : 'MgmtEth0/RSP0/CPU0/0',
'mac' : '5c:5e:ab:da:3c:f0',
'ip' : '172.17.17.1',
'age' : 1454496274.84
},
{
'interface': 'MgmtEth0/RSP0/CPU0/0',
'mac' : '66:0e:94:96:e0:ff',
'ip' : '172.17.17.2',
'age' : 1435641582.49
}
]
"""

proxy_output = __proxy__['napalm.call'](
'get_arp_table',
**{
}
)

if not proxy_output.get('result'):
return proxy_output

arp_table = proxy_output.get('out')

if interface:
arp_table = _filter_list(arp_table, 'interface', interface)

if ipaddr:
arp_table = _filter_list(arp_table, 'ip', ipaddr)

if macaddr:
arp_table = _filter_list(arp_table, 'mac', macaddr)

proxy_output.update({
'out': arp_table
})

return proxy_output


def ipaddrs():
'''
Returns IP addresses on the device
CLI example:
.. code-block:: bash
salt myminion net.ipaddrs
'''
return __proxy__['napalm.call'](
'get_interfaces_ip',
**{
}
)


def lldp(interface=''):

"""
returns LLDP neighbors
CLI example:
.. code-block:: bash
salt myminion net.lldp
salt myminion net.lldp interface='TenGigE0/0/0/8'
:param interface: interface name to filter on
Example output:
{
'TenGigE0/0/0/8': [
{
'parent_interface': u'Bundle-Ether8',
'interface_description': u'TenGigE0/0/0/8',
'remote_chassis_id': u'8c60.4f69.e96c',
'remote_system_name': u'switch',
'remote_port': u'Eth2/2/1',
'remote_port_description': u'Ethernet2/2/1',
'remote_system_description': u'''Cisco Nexus Operating System (NX-OS) Software 7.1(0)N1(1a)
TAC support: http://www.cisco.com/tac
Copyright (c) 2002-2015, Cisco Systems, Inc. All rights reserved.''',
'remote_system_capab': u'B, R',
'remote_system_enable_capab': u'B'
}
]
}
"""

proxy_output = __proxy__['napalm.call'](
'get_lldp_neighbors_detail',
**{
}
)

if not proxy_output.get('result'):
return proxy_output

lldp_neighbors = proxy_output.get('out')

if interface:
lldp_neighbors = {interface: lldp_neighbors.get(interface)}

proxy_output.update({
'out': lldp_neighbors
})

return proxy_output


def mac(address='', interface='', vlan=0):

"""
returns device MAC address table
CLI example:
.. code-block:: bash
salt myminion net.mac
salt myminion net.mac vlan=10
:param address: MAC address to filter on
:param interface: interface name to filter on
:param vlan: vlan identifier
Example output:
[
{
'mac' : '00:1c:58:29:4a:71',
'interface' : 'xe-3/0/2',
'static' : False,
'active' : True,
'moves' : 1,
'vlan' : 10,
'last_move' : 1454417742.58
},
{
'mac' : '8c:60:4f:58:e1:c1',
'interface' : 'xe-1/0/1',
'static' : False,
'active' : True,
'moves' : 2,
'vlan' : 42,
'last_move' : 1453191948.11
}
]
"""

proxy_output = __proxy__['napalm.call'](
'get_mac_address_table',
**{
}
)

if not proxy_output.get('result'):
# if negative, leave the output unchanged
return proxy_output

mac_address_table = proxy_output.get('out')

if vlan and isinstance(int, vlan):
mac_address_table = {vlan: mac_address_table.get(vlan)}

if address:
mac_address_table = _filter_dict(mac_address_table, 'mac', address)

if interface:
mac_address_table = _filter_dict(mac_address_table, 'interface', interface)

proxy_output.update({
'out': mac_address_table
})

return proxy_output

0 comments on commit 437b983

Please sign in to comment.