From b4f4a8346c3f1c0d49ca0da56bc4751d1a6aad0d Mon Sep 17 00:00:00 2001 From: Daniel Dayley Date: Tue, 1 Jun 2021 17:36:34 -0600 Subject: [PATCH] Added multiple filter support Hopefully doens't break anything running YOLOOOOOOOOOO --- README.md | 8 +++++--- bin/ifxlookup | 4 ++-- ifxlookup/ifxlookup.py | 36 +++++++++++++++++++++++++++--------- 3 files changed, 34 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 5a69f15..4344fd3 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ optional arguments: -c CONFIG, --config CONFIG Specify a config file (~/.config/ifxlookup.yml by default) -f FILTER, --filter FILTER - Apply a JSONPath filter to the results + Apply a JSONPath filter to the results (multiple filters may be specified) -j, --json Format output as json -cg, --vip Return VIP information about the subject (f5) -b, --bluecat Return network information about the subject (bluecat) @@ -76,6 +76,8 @@ IFXLookup may filter the results returned by any and all plugins by applying a [ ifxlookup -d -f '*.dns.mx' sling.com dish.com ``` +You can specify multiple filters with -f, however, all filters run on the results dataset separately. Filters cannot be stacked due to the nature of JSONPath. + #### Examples To find the DHCP assigned gateway for a the IP 10.124.24.130: @@ -174,9 +176,9 @@ Returns a map of plugins configured to use in the lookup. #### lookup() ```python -ifxlookup.IFXLookup.lookup(self,subjects,filter=None) +ifxlookup.IFXLookup.lookup(self,subjects,filters=None) ``` -Performs a search with the configured plugins and filter and returns a dictionary of search data. +Performs a search with the configured plugins and filters and returns a dictionary of search data. #### search_plugins(directory) ```python diff --git a/bin/ifxlookup b/bin/ifxlookup index e0c7081..8a02716 100755 --- a/bin/ifxlookup +++ b/bin/ifxlookup @@ -50,7 +50,7 @@ if __name__ == '__main__': # Gather Argument options parser = argparse.ArgumentParser(epilog=EXAMPLE_TEXT,formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument('-c', '--config', action='store', help='Specify a config file (~/.config/ifxlookup.yml by default)') - parser.add_argument('-f', '--filter', action='store', default=None, help='Apply a JSONPath filter to the results') + parser.add_argument('-f', '--filter', action='append', default=None, help='Apply a JSONPath filter to the results (multiple filters may be specified)') parser.add_argument('-j', '--json', action='store_true', help='Format output as json') # parser.add_argument('-l', '--link', action='store_true', help='Return physical link information about the subject') for delegate in available_plugins.values() : @@ -124,7 +124,7 @@ if __name__ == '__main__': search.set_debug_level(args.debug) # Run search - report = search.lookup(args.subjects,filter=args.filter) + report = search.lookup(args.subjects,filters=args.filter) if args.json : print(json.dumps(report)) else : diff --git a/ifxlookup/ifxlookup.py b/ifxlookup/ifxlookup.py index 74f569b..1242413 100755 --- a/ifxlookup/ifxlookup.py +++ b/ifxlookup/ifxlookup.py @@ -62,7 +62,12 @@ class IFXLookup(): """Generate map of ifxlookup runtime values that should be made available to plugins.""" return {'debug' : self._debug_level,'caching': self._caching} - def __filter_and_return(self,subjects,dataset,filter) : + def __apply_filter(self,dataset,jsonpath_filter) : + """Applies the given jsonpath filter to the dataset and returns the filtered results.""" + filtered_result = [x.value for x in jsonpath_filter.find(dataset)] + return filtered_result + + def __prepare_final(self,subjects,dataset,filters) : """Returns the submitted dataset, applying the given filter.""" final_result = {} if 'error' in dataset or 'warn' in dataset : @@ -76,11 +81,13 @@ class IFXLookup(): for plugin in [x for x in dataset if x != 'error' and x != 'warn'] : subjectdataset.update({plugin:dataset[plugin][subject]}) final_result.update({subject:subjectdataset}) - # Apply Filter - if filter : - jsonpath_filter = jsonpath_ng.parse(filter) - final_result = [x.value for x in jsonpath_filter.find(final_result)] - return final_result + # Apply Filters + if type(filters) != list : + raise TypeError('argument \'filters\' should be of type list') + filtered_result = [] + for filter in filters : + filtered_result.extend(self.__apply_filter(final_result, filter)) + return filtered_result def use_plugins(self,plugins,reload=False) : """Defines plugins that should be used in a lookup, optionally forcing them to reload.""" @@ -162,12 +169,22 @@ class IFXLookup(): self._caching = False return self - def lookup(self,subjects,filter=None) : - """Performs a search with the configured plugins and filter and returns a dictionary of search data.""" + def lookup(self,subjects,filter=None,filters=None) : + """Performs a search with the configured plugins and filters and returns a dictionary of search data.""" + # Filter argument provided for backwards compatibility, please use `filters` instead. hints = {} final_report = {} error_info = {} warn_info = {} + + # Clean and verify filters + if filter and not filters : + filters = [filter] + valid_filters = [] + for filter in filters : + new_filter = jsonpath_ng.parse(filter) + valid_filters.append(new_filter) + # Assert that each plugin has a config for delegatename,delegate in self._delegate_map.items() : if not delegatename in self._config.keys() : @@ -212,7 +229,8 @@ class IFXLookup(): # If caching is enabled prevent shutdown. Otherwise shutdown. if not self._caching : self.__shutdown_plugins() - return self.__filter_and_return(subjects,final_report,filter) + final = self.__prepare_final(subjects,final_report,valid_filters) + return final def finish(self) : """In the case that caching has been enabled, this enables the plugins to be manually shut down."""