11
11
12
12
from __future__ import absolute_import , division , print_function
13
13
14
+ import functools
14
15
from pprint import pformat
15
16
16
17
from ansible .errors import AnsibleError
45
46
description:
46
47
- The api_filter to use.
47
48
required: False
49
+ plugin:
50
+ description:
51
+ - The Netbox plugin to query
52
+ required: False
48
53
token:
49
54
description:
50
55
- The API token created through Netbox
98
103
- name: "Obtain secrets for R1-Device"
99
104
debug:
100
105
msg: "{{ query('netbox.netbox.nb_lookup', 'secrets', api_filter='device=R1-Device', api_endpoint='http://localhost/', token='<redacted>', key_file='~/.ssh/id_rsa') }}"
106
+
107
+ # Fetch bgp sessions for R1-device
108
+ tasks:
109
+ - name: "Obtain bgp sessions for R1-Device"
110
+ debug:
111
+ msg: "{{ query('netbox.netbox.nb_lookup', 'bgp_sessions',
112
+ api_filter='device=R1-Device',
113
+ api_endpoint='http://localhost/',
114
+ token='<redacted>',
115
+ plugin='mycustomstuff') }}"
116
+
117
+ msg: "{{ query('netbox.netbox.nb_lookup', 'secrets', api_filter='device=R1-Device', api_endpoint='http://localhost/', token='<redacted>', key_file='~/.ssh/id_rsa') }}"
101
118
"""
102
119
103
120
RETURN = """
@@ -187,6 +204,78 @@ def get_endpoint(netbox, term):
187
204
return netbox_endpoint_map [term ]["endpoint" ]
188
205
189
206
207
+ def build_filters (filters ):
208
+ """
209
+ This will build the filters to be handed to NetBox endpoint call if they exist.
210
+
211
+ Args:
212
+ filters (str): String of filters to parse.
213
+
214
+ Returns:
215
+ result (list): List of dictionaries to filter by.
216
+ """
217
+ filter = {}
218
+ args_split = split_args (filters )
219
+ args = [parse_kv (x ) for x in args_split ]
220
+ for arg in args :
221
+ for k , v in arg .items ():
222
+ if k not in filter :
223
+ filter [k ] = list ()
224
+ filter [k ].append (v )
225
+ else :
226
+ filter [k ].append (v )
227
+
228
+ return filter
229
+
230
+
231
+ def get_plugin_endpoint (netbox , plugin , term ):
232
+ """
233
+ get_plugin_endpoint(netbox, plugin, term)
234
+ netbox: a predefined pynetbox.api() pointing to a valid instance
235
+ of Netbox
236
+ plugin: a string referencing the plugin name
237
+ term: the term passed to the lookup function upon which the api
238
+ call will be identified
239
+ """
240
+ attr = "plugins.%s.%s" % (plugin , term )
241
+
242
+ def _getattr (netbox , attr ):
243
+ return getattr (netbox , attr )
244
+
245
+ return functools .reduce (_getattr , [netbox ] + attr .split ("." ))
246
+
247
+
248
+ def make_netbox_call (nb_endpoint , filters = None ):
249
+ """
250
+ Wrapper for calls to NetBox and handle any possible errors.
251
+
252
+ Args:
253
+ nb_endpoint (object): The NetBox endpoint object to make calls.
254
+
255
+ Returns:
256
+ results (object): Pynetbox result.
257
+
258
+ Raises:
259
+ AnsibleError: Ansible Error containing an error message.
260
+ """
261
+ try :
262
+ if filters :
263
+ results = nb_endpoint .filter (** filters )
264
+ else :
265
+ results = nb_endpoint .all ()
266
+ except pynetbox .RequestError as e :
267
+ if e .req .status_code == 404 and "plugins" in e :
268
+ raise AnsibleError (
269
+ "{0} - Not a valid plugin endpoint, please make sure to provide valid plugin endpoint." .format (
270
+ e .error
271
+ )
272
+ )
273
+ else :
274
+ raise AnsibleError (e .error )
275
+
276
+ return results
277
+
278
+
190
279
class LookupModule (LookupBase ):
191
280
"""
192
281
LookupModule(LookupBase) is defined by Ansible
@@ -200,6 +289,7 @@ def run(self, terms, variables=None, **kwargs):
200
289
netbox_private_key_file = kwargs .get ("key_file" )
201
290
netbox_api_filter = kwargs .get ("api_filter" )
202
291
netbox_raw_return = kwargs .get ("raw_data" )
292
+ netbox_plugin = kwargs .get ("plugin" )
203
293
204
294
if not isinstance (terms , list ):
205
295
terms = [terms ]
@@ -222,54 +312,39 @@ def run(self, terms, variables=None, **kwargs):
222
312
223
313
results = []
224
314
for term in terms :
225
-
226
- try :
227
- endpoint = get_endpoint (netbox , term )
228
- except KeyError :
229
- raise AnsibleError ("Unrecognised term %s. Check documentation" % term )
315
+ if netbox_plugin :
316
+ endpoint = get_plugin_endpoint (netbox , netbox_plugin , term )
317
+ else :
318
+ try :
319
+ endpoint = get_endpoint (netbox , term )
320
+ except KeyError :
321
+ raise AnsibleError (
322
+ "Unrecognised term %s. Check documentation" % term
323
+ )
230
324
231
325
Display ().vvvv (
232
326
u"Netbox lookup for %s to %s using token %s filter %s"
233
327
% (term , netbox_api_endpoint , netbox_api_token , netbox_api_filter )
234
328
)
235
329
236
330
if netbox_api_filter :
237
- args_split = split_args (netbox_api_filter )
238
- args = [parse_kv (x ) for x in args_split ]
239
- filter = {}
240
- for arg in args :
241
- for k , v in arg .items ():
242
- if k not in filter :
243
- filter [k ] = list ()
244
- filter [k ].append (v )
245
- else :
246
- filter [k ].append (v )
331
+ filter = build_filters (netbox_api_filter )
247
332
248
333
Display ().vvvv ("filter is %s" % filter )
249
334
250
- for res in endpoint .filter (** filter ):
251
-
252
- Display ().vvvvv (pformat (dict (res )))
253
-
254
- if netbox_raw_return :
255
- results .append (dict (res ))
256
-
257
- else :
258
- key = dict (res )["id" ]
259
- result = {key : dict (res )}
260
- results .extend (self ._flatten_hash_to_list (result ))
261
-
262
- else :
263
- for res in endpoint .all ():
264
-
265
- Display ().vvvvv (pformat (dict (res )))
335
+ # Make call to NetBox API and capture any failures
336
+ nb_data = make_netbox_call (
337
+ endpoint , filters = filter if netbox_api_filter else None
338
+ )
266
339
267
- if netbox_raw_return :
268
- results . append ( dict (res ))
340
+ for data in nb_data :
341
+ Display (). vvvvv ( pformat ( dict (data ) ))
269
342
270
- else :
271
- key = dict (res )["id" ]
272
- result = {key : dict (res )}
273
- results .extend (self ._flatten_hash_to_list (result ))
343
+ if netbox_raw_return :
344
+ results .append (dict (data ))
345
+ else :
346
+ key = dict (data )["id" ]
347
+ result = {key : dict (data )}
348
+ results .extend (self ._flatten_hash_to_list (result ))
274
349
275
350
return results
0 commit comments