You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
93 lines
3.3 KiB
93 lines
3.3 KiB
import sys
|
|
import os
|
|
|
|
from .base_util import is_valid_identifier, get_apps_path
|
|
from .searchinfo_util import should_use_btool, validate_searchinfo_for_btool
|
|
from .algo_loader import AlgoLoader, BtoolAlgoLoadingStrategy, RestAlgoLoadingStrategy
|
|
import cexc
|
|
|
|
logger = cexc.get_logger(__name__)
|
|
|
|
|
|
def load_algos_from_searchinfo(searchinfo):
|
|
"""
|
|
Load the list of algorithms supported from Splunk
|
|
|
|
Args:
|
|
searchinfo (dict): information required for search
|
|
|
|
Returns:
|
|
(dict): mapping of algorithm name to a dict containing
|
|
information about the algo (app, disabled, package)
|
|
|
|
"""
|
|
if not searchinfo:
|
|
return {}
|
|
|
|
algo_loader = algo_loader_from_searchinfo(searchinfo)
|
|
return algo_loader.load_algos()
|
|
|
|
|
|
def algo_loader_from_searchinfo(searchinfo):
|
|
"""
|
|
Create an AlgoLoader object with the correct algo loading strategy based on information from the searchinfo
|
|
|
|
Args:
|
|
searchinfo (dict): information required for search
|
|
|
|
Returns:
|
|
(AlgoLoader): AlgoLoader instance with the correct algo loading strategy
|
|
|
|
"""
|
|
if should_use_btool(searchinfo):
|
|
is_valid, err = validate_searchinfo_for_btool(searchinfo)
|
|
if is_valid:
|
|
# On an indexer, we need to iterate through the roles and merge the results manually
|
|
# since btool does not have user-to-role mapping there. Pass the roles instead of the username.
|
|
algo_loader = AlgoLoader(BtoolAlgoLoadingStrategy(searchinfo))
|
|
else:
|
|
raise RuntimeError('Failed to load algorithm on remote Splunk: %s' % err)
|
|
else:
|
|
# On a search head or a standalone node, REST API will get us the correctly merged results.
|
|
algo_loader = AlgoLoader(RestAlgoLoadingStrategy(searchinfo))
|
|
return algo_loader
|
|
|
|
|
|
def initialize_algo_class(algo_name, searchinfo):
|
|
"""Import and initialize the algorithm.
|
|
|
|
Args:
|
|
algo_name (str): the usual suspect
|
|
searchinfo (dict): information required for search
|
|
|
|
Returns:
|
|
algo_class (class): the suspect's class
|
|
|
|
"""
|
|
if not is_valid_identifier(algo_name):
|
|
raise RuntimeError('Failed to load algorithm with an invalid name: %s' % algo_name)
|
|
|
|
all_algos = load_algos_from_searchinfo(searchinfo)
|
|
algo = {}
|
|
try:
|
|
if algo_name in all_algos:
|
|
algo = all_algos[algo_name]
|
|
if not algo['disabled']:
|
|
bundle_path = searchinfo.get('bundle_path')
|
|
new_sys_path = os.path.join(get_apps_path(bundle_path), algo['app'], 'bin')
|
|
if new_sys_path not in sys.path:
|
|
sys.path.append(new_sys_path)
|
|
algos = __import__("%s.%s" % (algo['package'], algo_name))
|
|
else:
|
|
raise RuntimeError('Algorithm "%s" is disabled' % algo_name)
|
|
else:
|
|
raise RuntimeError('Algorithm "%s" cannot be loaded' % algo_name)
|
|
algo_package = getattr(algos, algo_name)
|
|
algo_class = getattr(algo_package, algo_name)
|
|
return algo_class
|
|
except (ImportError, AttributeError) as e:
|
|
package_name = algo.get('package', '')
|
|
algo_name = '{}.{}'.format(package_name, algo_name) if package_name else algo_name
|
|
logger.debug(e)
|
|
raise RuntimeError('Failed to load algorithm "%s"' % algo_name)
|