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.

138 lines
5.9 KiB

# Copyright (C) 2005-2025 Splunk Inc. All Rights Reserved.
import re
from ITOA import itoa_common as utils, setup_logging
from ITOA.saved_search_utility import SavedSearch
class ItsiAtAdSearchBase(object):
"""
Implements common functionality for operating on saved searches related
to ITSI anomaly detection and adaptive thresholding features.
Mostly contains CRUD operations and utility functions.
"""
log_prefix = '[ITSI AD Search] '
def __init__(self, session_key, logger=None):
self.session_key = session_key
self.logger = logger if logger else setup_logging.logger
def _make_search_name_suffix(self, training_window_id, object_type="kpi"):
"""
Generate name for AD search stanza
@param training_window_id: training window string
@param object_type: object_type to make saved search name. Valid values: kpi, entity
@returns: name for AD search stanza
"""
return 'search_{0}_{1}'.format(object_type, training_window_id.replace("-", "minus").replace(" ", ""))
def _get_all_searches(self, filter_func):
"""
@param filter_func: boolean-valued function; if returns True when applied to saved search stanza name,
include it in the output
@returns: dict of saved searches keyed by stanza name
"""
saved_searches = {}
results = utils.get_conf(self.session_key, 'savedsearches')
if utils.is_valid_dict(results) and \
utils.is_valid_dict(results.get('response')) and \
utils.is_valid_str(results['response'].get('status')) and \
(results['response']['status'] == '200'):
content = utils.validate_json('', results.get('content', []))
# Filter down to KPI saved searches and hash by ID
for saved_search in content.get('entry', []):
if not filter_func(saved_search['name']):
continue
saved_searches[saved_search['name']] = saved_search
return saved_searches
def to_minutes(self, timespec):
"""
Convert a limited set of time specifiers to minutes
@param timespec: relative time specifier string of the form '-<num><unit>' where unit is one of 'm', 'd', 'h', 'w'
"""
to_minutes = {'m': 1, 'h': 60, 'd': 1440, 'w': 10080}
m = re.match(r"-(\d+)([dhmw])", timespec)
units = m.group(2)
return int(m.group(1)) * to_minutes[units]
def to_days(self, timespec):
"""
Convert a limited set of time specifiers to days, rounded down to an integer number
@param timespec: relative time specifier string of the form '-<num><unit>' where unit is one of 'm', 'd', 'h', 'w'
"""
return self.to_minutes(timespec) // 1440
def make_saved_search_params(self, name, search, et, kpi_list):
"""
Helper method to create KV pairs for the saved search stanza. Must be implemented by subclasses.
@param name: search stanza name
@param search: search string
@param et: earliest time (relative timespec)
@param kpi_list: list of KPI IDs
@returns: dict of key/value pairs for the saved search stanza
"""
raise NotImplementedError()
def _parse_response(self, response, success_msg, err_msg):
if not (int(response.get('status')) == 200 or int(response.get('status')) == 201):
self.logger.debug(err_msg)
return False
else:
self.logger.debug(success_msg)
return True
def create_saved_search(self, search_name, search_string, et, kpi_list=[], cron_schedule='0 0 * * *'):
"""
Create AD or AT search stanza
@param search_name: search stanza name
@param search_string: saved search to write
@param et: dispatch earliest time
@param kpi_list: list of KPI IDs
@returns: boolean indicating operation success
"""
stanza = self.make_saved_search_params(name=search_name,
search=search_string,
et=et, kpi_list=kpi_list, cron_schedule=cron_schedule)
result = SavedSearch.update_search(self.session_key, search_name, 'itsi', 'nobody', **stanza)
if result:
self.logger.info("Successfully created saved search=%s", search_name)
else:
self.logger.error("Failed to create search=%s", search_name)
return result
def update_saved_search(self, search_name, search_string, et, kpi_list, cron_schedule='0 0 * * *'):
"""
Update AD or AT search stanza
@param search_name: search stanza name
@param search_string: saved search to write
@param et: dispatch earliest time
@param kpi_list: list of KPI IDs
@returns: boolean indicating operation success
"""
stanza = self.make_saved_search_params(name=search_name,
search=search_string,
et=et, kpi_list=kpi_list, cron_schedule=cron_schedule)
result = SavedSearch.update_search(self.session_key, search_name, 'itsi', 'nobody', **stanza)
if result:
self.logger.info("Successfully updated saved search=%s", search_name)
else:
self.logger.error("Failed to update saved search=%s", search_name)
return result
def delete_saved_search(self, search_name):
"""
Delete AD or AT search stanza
@param search_name: search stanza name
@returns: boolean indicating operation success
"""
result = SavedSearch.delete_search(self.session_key, search_name)
if result:
self.logger.info("Successfully deleted saved search %s.", search_name)
else:
self.logger.error("Failed to delete saved search %s.", search_name)
return result