Source code for _roster.netbox
# -*- coding: utf-8 -*-
'''
Load devices from `NetBox <https://github.com/digitalocean/netbox>`__, and make
them available for salt-ssh or salt-sproxy (or any other program that doesn't
require (Proxy) Minions running).
Make sure that the following options are configured on the Master:
.. code-block:: yaml
netbox:
url: <NETBOX_URL>
token: <NETBOX_USERNAME_API_TOKEN (OPTIONAL)>
keyfile: </PATH/TO/NETBOX/KEY (OPTIONAL)>
If you want to pre-filter the devices, so it won't try to pull the whole
database available in NetBox, you can configure another key, ``filters``, under
``netbox``, e.g.,
.. code-block:: yaml
netbox:
url: <NETBOX_URL>
filters:
site: <SITE>
status: <STATUS>
.. hint::
You can use any NetBox field as a filter.
.. important::
In NetBox v2.6 the default view permissions changed, so ``salt-sproxy`` may
not able to get the device list from NetBox by default.
Add ``EXEMPT_VIEW_PERMISSIONS = ['*']`` to the ``configuration.py`` NetBox
file to change this behavior.
See https://github.com/netbox-community/netbox/releases/tag/v2.6.0 for more
information
'''
# Import Python libs
from __future__ import absolute_import, print_function, unicode_literals
import logging
try:
import pynetbox # pylint: disable=unused-import
HAS_PYNETBOX = True
except ImportError:
HAS_PYNETBOX = False
import salt_sproxy._roster
__virtualname__ = 'netbox'
log = logging.getLogger(__name__)
def __virtual__():
if not HAS_PYNETBOX:
return (False, 'Please install pynetbox to be able to use the NetBox Roster')
return __virtualname__
def _setval(key, val, dict_=None, delim=':'):
'''
Set a value under the dictionary hierarchy identified
under the key. The target 'foo:bar:baz' returns the
dictionary hierarchy {'foo': {'bar': {'baz': {}}}}.
'''
if not dict_:
dict_ = {}
prev_hier = dict_
dict_hier = key.split(delim)
for each in dict_hier[:-1]:
if isinstance(each, str):
if each not in prev_hier:
prev_hier[each] = {}
prev_hier = prev_hier[each]
else:
prev_hier[each] = [{}]
prev_hier = prev_hier[each]
prev_hier[dict_hier[-1]] = val
return dict_
[docs]def targets(tgt, tgt_type='glob', **kwargs):
'''
Return the targets from NetBox.
'''
netbox_filters = __opts__.get('netbox', {}).get('filters', {})
netbox_filters.update(**kwargs)
filtered = False
if tgt_type == 'list' or (
tgt_type == 'glob' and not any([char in tgt for char in '*?[!'])
):
netbox_filters['name'] = tgt
filtered = True
elif tgt_type == 'grain' and tgt.startswith('netbox:'):
levels = tgt.split('netbox:')[1].split(':')
if len(levels) > 2:
netbox_filters[levels[0]] = _setval(':'.join(levels[1:-1]), levels[-1])
filtered = True
elif len(levels) == 2:
netbox_filters[levels[0]] = levels[1]
filtered = True
log.debug('Querying NetBox with the following filters')
log.debug(netbox_filters)
netbox_devices = __runner__['salt.cmd'](
'netbox.filter', 'dcim', 'devices', **netbox_filters
)
pool = {
device['name']: {'minion_opts': {'grains': {'netbox': device}}}
for device in netbox_devices
}
if filtered:
return pool
pool = salt_sproxy._roster.load_cache(
pool, __runner__, __opts__, tgt, tgt_type=tgt_type
)
engine = salt_sproxy._roster.TGT_FUN[tgt_type]
return engine(pool, tgt, opts=__opts__)