# Copyright (C) 2005-2025 Splunk Inc. All Rights Reserved. import json import sys import time from splunk import ResourceNotFound from splunk.clilib.bundle_paths import make_splunkhome_path sys.path.append(make_splunkhome_path(['etc', 'apps', 'SA-ITOA', 'lib'])) sys.path.append(make_splunkhome_path(['etc', 'apps', 'SA-ITOA', 'lib', 'SA_ITOA_app_common'])) import itsi_py3 from ITOA.setup_logging import logger as itsi_logger from ITOA.itoa_common import is_feature_enabled from ITOA.saved_search_utility import SavedSearch from ITOA.event_management.itsi_data_integration import ItsiDataIntegration from ITOA.event_management.notable_event_aggregation_policy import NotableEventAggregationPolicy from ITOA.event_management.notable_event_utils import get_collection_name_for_event_management_objects, \ NotableEventConfiguration sys.path.append(make_splunkhome_path(['etc', 'apps', 'SA-UserAccess', 'lib'])) from user_access_utils import UserAccess class NotableEventValidator(object): """ Notable event validator """ def __init__(self, session_key, logger, required_keys=None): self.session_key = session_key self.owner_key = 'owner' self.status_key = 'status' self.severity_key = 'severity' if required_keys is None: self.required_keys = ['_time', 'mod_time', 'title', self.owner_key, self.status_key, self.severity_key] else: self.required_keys = required_keys if logger: self.logger = logger else: raise ValueError('`logger` is not provided.') self.notable_configuration_object = NotableEventConfiguration(session_key, logger) self.valid_owners = self.notable_configuration_object.get_owners() self.valid_statuses = self.notable_configuration_object.get_statuses() self.valid_severities = self.notable_configuration_object.get_severities() def validate_schema(self, data): """ Validate schema before user CURD operation on notable event @type data: dict @param data: data which hold notable schema to create @rtype: bool @return: True - if data contains all required fields, False - otherwise or throw exception """ # Check for status, owner and severity is defined, otherwise set to default. if data.get(self.owner_key) is None or data.get(self.owner_key) == '': self.logger.info('No owner is being set for event title=%s, hence setting to default owner=%s.', data.get('title'), self.notable_configuration_object.get_default_owner()) data[self.owner_key] = self.notable_configuration_object.get_default_owner() if data.get(self.status_key) is None or data.get(self.status_key) == '': self.logger.info('No status is being set for event title=%s, hence setting to default status=%s.', data.get('title'), self.notable_configuration_object.get_default_status()) data[self.status_key] = self.notable_configuration_object.get_default_status() if data.get(self.severity_key) is None or data.get(self.severity_key) == '': self.logger.info('No severity is being set for event title=%s, hence setting to default severity=%s.', data.get('title'), self.notable_configuration_object.get_default_severity()) data[self.severity_key] = self.notable_configuration_object.get_default_severity() for key in self.required_keys: if key not in data: message = '%s key does not exist in the data=%s.' % (key, str(data)) self.logger.error(message) raise ValueError(message) # Make sure status, severity value is str data[self.owner_key] = str(data.get(self.owner_key, '')) data[self.status_key] = str(data.get(self.status_key, '')) data[self.severity_key] = str(data.get(self.severity_key, '')) # Lets have more logging and proper error if validation failed. is_validate_owner = self.check_owner(data.get(self.owner_key)) if not is_validate_owner: warning_message = ('Invalid owner={0} for event title={1}. ' 'Unable to find owner in valid Splunk user list, ' 'hence setting to default owner={2}.').format( data.get(self.owner_key), data.get('title'), self.notable_configuration_object.get_default_owner()) self.logger.warning(warning_message) data[self.owner_key] = self.notable_configuration_object.get_default_owner() is_validate_status = self.check_status(data.get(self.status_key)) if not is_validate_status: warning_message = ('Invalid status={0} for event title={1}. ' 'Unable to find status in itsi_notable_event_status.conf, ' 'hence setting to default status={2}.').format( data.get(self.status_key), data.get('title'), self.notable_configuration_object.get_default_status()) self.logger.warning(warning_message) data[self.status_key] = self.notable_configuration_object.get_default_status() is_validate_severity = self.check_severity(data.get(self.severity_key)) if not is_validate_severity: warning_message = ('Invalid severity={0} for event title={1}. ' 'Unable to find severity in itsi_notable_event_severity.conf, ' 'hence setting to default severity={2}.').format( data.get(self.severity_key), data.get('title'), self.notable_configuration_object.get_default_severity()) self.logger.warning(warning_message) data[self.severity_key] = self.notable_configuration_object.get_default_severity() return is_validate_owner or is_validate_status or is_validate_severity def check_severity(self, severity): """ Check severity @type severity: basestring @param severity: severity @rtype: bool @return: True if valid severity otherwise False """ return severity in self.valid_severities def check_status(self, status): """ Check status @type status: basestring @param status: Status @rtype: bool @return: True if valid status otherwise False """ return status in self.valid_statuses def check_owner(self, owner): """ Check owner is valid or not @type owner: basestring @param owner: owner @rtype: bool @return: True if valid owner otherwise False """ return owner in self.valid_owners class NotableEventDefaultPoliciesLoader(object): """ This class is being used to load default aggregation policy """ DEFAULT_POLICY = """ { "_key": "itsi_default_policy", "group_title": "%title%", "group_description": "%description%", "group_status": "%status%", "group_assignee": "%owner%", "disabled": 0, "is_default": 1, "object_type": "notable_aggregation_policy", "title": "Default Policy", "description": "Applies to events that do not meet the criteria of any other active policy.", "split_by_field": "source", "priority": 5, "group_severity": "%severity%", "filter_criteria": { "condition": "OR", "items": [] }, "breaking_criteria": { "condition": "OR", "items": [ { "type": "pause", "config": { "limit": "7200" } } ] }, "rules": [] } """ DEFAULT_SNMP_POLICY = """ { "_key": "itsi_default_snmp_policy", "group_title": "%title%", "group_description": "%description%", "group_status": "%status%", "group_assignee": "%owner%", "disabled": 1, "is_default": 0, "object_type": "notable_aggregation_policy", "title": "Default SNMP Policy", "description": "Aggregation policy for SNMP traps", "split_by_field": "node,description", "priority": "", "group_severity": "%severity%", "filter_criteria": { "items": [ { "type": "clause", "config": { "items": [ { "type": "notable_event_field", "config": { "operator": "=", "field": "node", "value": "*" } }, { "type": "notable_event_field", "config": { "operator": "=", "field": "description", "value": "*" } } ], "condition": "AND" } } ], "condition": "OR" }, "breaking_criteria": { "items": [ { "type": "clause", "config": { "items": [ { "type": "notable_event_field", "config": { "operator": "=", "field": "severity", "value": "2" } } ], "condition": "AND" } } ], "condition": "OR" }, "rules": [ ] } """ NORMALIZED_AGGREGATION_POLICY = """ { "_key": "normalized_aggregation_policy", "group_title": "Normalized Alert for %itsiInstance% (%itsiSubInstance%) : %itsiAlert%", "group_description": "%last_description%", "group_status": "%status%", "group_assignee": "%owner%", "disabled": 0, "is_default": 0, "object_type": "notable_aggregation_policy", "title": "Normalized Policy (Splunk App for Infrastructure)", "description": "Applies to events that contain ITSI normalized fields.", "split_by_field": "itsiAlert,itsiInstance", "priority": "", "group_severity": "%last_severity%", "group_instruction": "%last_instruction%", "filter_criteria": { "items": [ { "config": { "items": [ { "config": { "operator": "=", "field": "itsiAlert", "value": "*" }, "type": "notable_event_field" }, { "config": { "operator": "=", "field": "itsiInstance", "value": "*" }, "type": "notable_event_field" }, { "config": { "operator": "=", "field": "itsiSubInstance", "value": "*" }, "type": "notable_event_field" }, { "config": { "operator": "=", "field": "itsiSeverity", "value": "*" }, "type": "notable_event_field" } ], "condition": "AND" }, "type": "clause" } ], "condition": "OR" }, "breaking_criteria": { "items": [ { "config": { "limit": "3600" }, "type": "pause" }, { "config": { "items": [ { "config": { "operator": "=", "field": "severity", "value": "2" }, "type": "notable_event_field" } ], "condition": "AND" }, "type": "clause" } ], "condition": "OR" }, "rules": [ { "_key": "normalized_aggregation_policy_action_1", "priority": 5, "activation_criteria": { "items": [ { "type": "breaking_criteria" }, { "config": { "operator": ">=", "limit": "2" }, "type": "notable_event_count" } ], "condition": "AND" }, "actions": [ { "items": [ { "execution_criteria": { "execute_on": "GROUP" }, "type": "notable_event_change", "config": { "field": "status", "value": "4" } } ], "condition": "AND" } ], "title": "", "description": "" }, { "_key": "normalized_aggregation_policy_action_2", "priority": 5, "activation_criteria": { "items": [ { "type": "breaking_criteria" }, { "config": { "operator": "==", "limit": "1" }, "type": "notable_event_count" } ], "condition": "AND" }, "actions": [ { "items": [ { "execution_criteria": { "execute_on": "GROUP" }, "type": "notable_event_change", "config": { "field": "status", "value": "5" } } ], "condition": "AND" } ], "title": "", "description": "" } ] } """ ENTITY_TYPE_ALERT_AGGREGATION_POLICY = """ { "_key": "entity_type_ootb_aggregation_policy", "group_title": "Entity Type Alerts: %entity_type%, Severity: %itsiSeverity%", "group_description": "Alerts for %entity_type% with Severity level %itsiSeverity%", "group_status": "%status%", "group_assignee": "%owner%", "disabled": 0, "is_default": 0, "object_type": "notable_aggregation_policy", "title": "Entity Type Alerts", "description": "Applies to events for entities that match a custom or out-of-box Entity Type", "split_by_field": "entity_type,itsiSeverity", "priority": "", "group_severity": "%last_severity%", "group_instruction": "%last_instruction%", "filter_criteria": { "items": [ { "config": { "items": [ { "config": { "operator": "=", "field": "entity_type", "value": "*" }, "type": "notable_event_field" }, { "config": { "operator": "=", "field": "itsiAlert", "value": "*" }, "type": "notable_event_field" }, { "config": { "operator": "=", "field": "itsiInstance", "value": "*" }, "type": "notable_event_field" }, { "config": { "operator": "=", "field": "itsiSeverity", "value": "*" }, "type": "notable_event_field" }, { "config": { "operator": "=", "field": "alert_source", "value": "entity_type" }, "type": "notable_event_field" } ], "condition": "AND" }, "type": "clause" } ], "condition": "OR" }, "breaking_criteria": { "items": [ { "config": { "limit": "3600" }, "type": "pause" }, { "config": { "items": [ { "config": { "operator": "=", "field": "severity", "value": "2" }, "type": "notable_event_field" } ], "condition": "AND" }, "type": "clause" } ], "condition": "OR" }, "rules": [ { "_key": "entity_type_ootb_aggregation_policy_action_1", "priority": 5, "activation_criteria": { "items": [ { "type": "breaking_criteria" }, { "config": { "operator": ">=", "limit": "2" }, "type": "notable_event_count" } ], "condition": "AND" }, "actions": [ { "items": [ { "execution_criteria": { "execute_on": "GROUP" }, "type": "notable_event_change", "config": { "field": "status", "value": "4" } } ], "condition": "AND" } ], "title": "Resolve episodes that are broken and have greater than or equal to 2 events", "description": "When the episode is broken, and the number of events in the episode is >= 2, \ change the episode status to Resolved." }, { "_key": "entity_type_ootb_aggregation_policy_action_2", "priority": 5, "activation_criteria": { "items": [ { "type": "breaking_criteria" }, { "config": { "operator": "==", "limit": "1" }, "type": "notable_event_count" } ], "condition": "AND" }, "actions": [ { "items": [ { "execution_criteria": { "execute_on": "GROUP" }, "type": "notable_event_change", "config": { "field": "status", "value": "5" } } ], "condition": "AND" } ], "title": "Close episodes that are broken which have only 1 event.", "description": "If the episode is broken, and the episode has only 1 event, \ then change the episode status to Closed." } ] } """ KPI_ALERTING_POLICY = """ { "_key": "kpi_alerting_policy", "_user": "nobody", "_owner": "nobody", "title": "KPI Alerting Policy", "group_title": "KPI Alerts from Service: %service_title%", "sub_group_limit": "", "group_assignee": "%last_owner%", "group_status": "%last_status%", "breaking_criteria": { "condition": "OR", "items": [ { "type": "pause", "config": { "limit": "3600" } } ] }, "disabled": 0, "is_default": 0, "priority": "", "identifying_name": "kpi alerting policy", "split_by_field": "service_ids", "rules": [ ], "object_type": "notable_aggregation_policy", "description": "Aggregation policy for KPI state-change alerts", "source_itsi_da": "itsi", "group_description": "Grouped alerts from service %service_title%; most recent alert from KPI %kpi_title%", "group_severity": "%last_severity%", "group_instruction": "%last_instruction%", "filter_criteria": { "condition": "OR", "items": [ { "type": "clause", "config": { "condition": "AND", "items": [ { "type": "notable_event_field", "config": { "value": "*", "operator": "=", "field": "kpiid" } }, { "type": "notable_event_field", "config": { "field": "alert_type", "operator": "=", "value": "KPI alert" } } ] } } ] } } """ KPI_DRIFT_POLICY = """ { "_key": "kpi_drift_policy", "_user": "nobody", "_owner": "nobody", "title": "KPI drift policy", "description": "Aggregation policy for KPI drift alerts", "mod_time": 1720482892.341328, "source_itsi_da": "itsi", "disabled": 0, "split_by_field": "kpiid,drift_type,start_time", "priority": "", "is_default": 0, "sub_group_limit": "", "filter_criteria": { "condition": "OR", "items": [ { "type": "clause", "config": { "items": [ { "type": "notable_event_field", "config": { "field": "kpiid", "operator": "=", "value": "*" } }, { "type": "notable_event_field", "config": { "field": "source", "operator": "=", "value": "DriftDetection" } } ], "condition": "AND" } } ] }, "breaking_criteria": { "condition": "OR", "items": [ { "type": "clause", "config": { "items": [ { "type": "notable_event_field", "config": { "field": "alert_type", "operator": "=", "value": "clearing" } } ], "condition": "AND" } }, { "type": "duration", "config": { "limit": 7776000 } } ] }, "rules": [ { "_key": "kpi_drift_policy_rule_1", "runOnce": false, "title": "", "description": "", "priority": 5, "activation_criteria": { "condition": "AND", "items": [ { "type": "breaking_criteria" } ] }, "actions": [ { "condition": "AND", "items": [ { "execution_criteria": { "execute_on": "GROUP" }, "config": { "field": "status", "value": "5" }, "type": "notable_event_change" } ] } ] } ], "group_assignee": "%owner%", "group_status": "%status%", "group_instruction": "%itsi_instruction%", "group_custom_instruction": "", "group_dashboard": "", "group_dashboard_context": "first", "run_time_based_actions_once": 0, "group_severity": "%last_severity%", "group_title": "%last_title%", "group_description": "%last_description%", "object_type": "notable_aggregation_policy", "identifying_name": "kpi drift policy" } """ def __init__(self, session_key, logger=None): if not isinstance(session_key, itsi_py3.string_type): raise TypeError('Invalid session key.') self.session_key = session_key self.logger = logger if logger is not None else itsi_logger self.notable_event_aggregator = NotableEventAggregationPolicy(session_key, is_validate=False) def upload_default_policies(self): """ @rtype: bool @return: True/False - if default policies are loaded successfully or not """ default_success = self.upload_policy("itsi_default_policy", self.DEFAULT_POLICY) normalized_success = self.upload_policy("normalized_aggregation_policy", self.NORMALIZED_AGGREGATION_POLICY) snmp_success = self.upload_policy("itsi_default_snmp_policy", self.DEFAULT_SNMP_POLICY) kpi_alert_success = self.upload_policy("kpi_alerting_policy", self.KPI_ALERTING_POLICY) entity_type_success = self.upload_policy("entity_type_ootb_aggregation_policy", self.ENTITY_TYPE_ALERT_AGGREGATION_POLICY) kpi_drift_success = self.upload_policy("kpi_drift_policy", self.KPI_DRIFT_POLICY) return default_success and normalized_success and snmp_success and kpi_alert_success and entity_type_success and kpi_drift_success def upload_policy(self, _id, policy): """ Upload policy @type _id: basestring @param _id: Aggregation policy id @type policy: basestring @param policy: Aggregation policy JSON string @rtype: bool @return: True/False - if policy is loaded successfully or not """ if not self.notable_event_aggregator.storage_interface.wait_for_storage_init(self.session_key): raise Exception('KV store failed to initialize in time.') try: result = self.notable_event_aggregator.get(_id) update_policy = False if result: if _id == "normalized_aggregation_policy" or _id == "entity_type_ootb_aggregation_policy": for actions in result['rules']: if '_key' not in actions or actions.get('_key') == "": update_policy = True if update_policy: ret = self.notable_event_aggregator.update(_id, json.loads(policy)) return True if ret else False else: self.logger.info('Action rule key Found for %s' % _id) return True else: self.logger.info('Found %s' % _id) return True else: self.logger.info('Could not find %s' % _id) raise ResourceNotFound('%s does not exist, this is expected when ITSI is first installed.' % _id) except ResourceNotFound as e: # load now self.logger.exception(e) self.logger.info('creating policy because we did not find %s', _id) ret = self.notable_event_aggregator.create(json.loads(policy)) # note this is not object type o_type = 'notable_event_aggregation_policy' success, rval = UserAccess.bulk_update_perms( object_ids=[_id], acl={'read': ['*'], 'write': ['*'], 'delete': []}, object_app='itsi', object_type=o_type, object_storename=get_collection_name_for_event_management_objects(o_type), session_key=self.session_key, logger=self.logger ) if not success: self.logger.error('Unable to save acl for %s. Response: `%s`', _id, rval) else: self.logger.info('Successfully saved acl for %s. Response:`%s`', _id, rval) return True if ret else False class CorrelationSearchDefaultAclLoader(object): """ This class sets the ACL permissions for the default correlation searches 'Monitor Critical Services Based on Health Score', 'Splunk App for Infrastructure Alerts', and 'Normalized Correlation Search' """ DEFAULT_ACL = {'read': ['*'], 'write': ['*'], 'delete': ['*']} DEFAULT_CS_ACL = {'read': ['*'], 'write': ['*'], 'delete': []} def __init__(self, session_key, logger=None): if not isinstance(session_key, itsi_py3.string_type): raise TypeError('Invalid session key.') self.session_key = session_key self.logger = logger if logger is not None else itsi_logger self.retrys = 120 def default_acl_loader(self): """ Set perms for default correlation searches @return: """ correlation_search_ids = ['Monitor Critical Services Based on Health Score', 'Splunk App for Infrastructure Alerts', 'Normalized Correlation Search', 'SNMP Traps', 'BMC Remedy Bidirectional Ticketing', 'Bidirectional Ticketing', 'Jira Bidirectional Ticketing', 'High Scale EA Backfill'] for id in correlation_search_ids: _id = id o_type = 'correlation_search' rval = 'Already created' perms = UserAccess.get_perms( object_id=_id, object_app='itsi', object_type=o_type, object_storename=get_collection_name_for_event_management_objects(o_type), session_key=self.session_key, logger=self.logger, object_owner='nobody' ) if _id == 'Bidirectional Ticketing' and not is_feature_enabled('itsi-bidirectional-ticketing', self.session_key): if perms: disabled_search = SavedSearch.update_search(self.session_key, _id, disabled=1) remove_perms = UserAccess.delete_perms( object_id=_id, object_app='itsi', object_type=o_type, object_storename=get_collection_name_for_event_management_objects(o_type), session_key=self.session_key, logger=self.logger, object_owner='nobody' ) if disabled_search and remove_perms: self.logger.info('Successfully removed acl and disabled %s because itsi-bidirectional-ticketing' + ' feature flag has been disabled', _id) else: self.logger.error('Failed to remove acl and disable %s', _id) continue if _id == 'BMC Remedy Bidirectional Ticketing' and not is_feature_enabled( 'itsi-remedy-bidirectional-ticketing', self.session_key): if perms: disabled_search = SavedSearch.update_search(self.session_key, _id, disabled=1) remove_perms = UserAccess.delete_perms( object_id=_id, object_app='itsi', object_type=o_type, object_storename=get_collection_name_for_event_management_objects(o_type), session_key=self.session_key, logger=self.logger, object_owner='nobody' ) if disabled_search and remove_perms: self.logger.info('Successfully removed acl and disabled %s because' 'itsi-remedy-bidirectional-ticketing feature flag has been disabled', _id) else: self.logger.error('Failed to remove acl and disable %s', _id) continue if _id == 'Jira Bidirectional Ticketing' and not is_feature_enabled( 'itsi-jira-bidirectional-ticketing', self.session_key): if perms: disabled_search = SavedSearch.update_search(self.session_key, _id, disabled=1) remove_perms = UserAccess.delete_perms( object_id=_id, object_app='itsi', object_type=o_type, object_storename=get_collection_name_for_event_management_objects(o_type), session_key=self.session_key, logger=self.logger, object_owner='nobody' ) if disabled_search and remove_perms: self.logger.info('Successfully removed acl and disabled %s because' 'itsi-jira-bidirectional-ticketing feature flag has been disabled', _id) else: self.logger.error('Failed to remove acl and disable %s', _id) continue if _id == 'High Scale EA Backfill': if perms: disabled_search = SavedSearch.update_search(self.session_key, _id, disabled=1) remove_perms = UserAccess.delete_perms( object_id=_id, object_app='itsi', object_type=o_type, object_storename=get_collection_name_for_event_management_objects(o_type), session_key=self.session_key, logger=self.logger, object_owner='nobody' ) if disabled_search and remove_perms: self.logger.info('Successfully removed acl and disabled %s', _id) else: self.logger.error('Failed to remove acl and disable %s', _id) continue while not perms and self.retrys > 0: self.logger.info('Trying to save acl for %s.', _id) success, rval = UserAccess.update_perms( object_id=_id, acl=self.DEFAULT_CS_ACL, object_app='itsi', object_type=o_type, object_storename=(get_collection_name_for_event_management_objects(o_type)), session_key=self.session_key, logger=self.logger ) perms = UserAccess.get_perms( object_id=_id, object_app='itsi', object_type=o_type, object_storename=get_collection_name_for_event_management_objects(o_type), session_key=self.session_key, logger=self.logger, object_owner='nobody' ) self.retrys -= 1 time.sleep(0.5) if not perms: self.logger.error( 'Unable to save acl for %s. Response: `%s`', _id, rval) else: self.logger.info( 'Successfully saved acl for %s. Response:`%s`', _id, rval) class DefaultDataIntegrationConnectionLoader(object): """ This class is being used to load default Data Integration connections. """ OLLY_CONNECTION = { "data_source": "o11y", "ingestion_method": { "type": "INDEXED_DATA", "value": 'index=main app=splunk_o11y_cloud', "time_range": { "earliest": "-24h", "latest": "now" } }, "mapped_fields": { "src": { "name": "src", "display_name": "Source", "type": "source_field", "input_type": "composition", "values": [ "{src}" ], "default_value": "o11y" }, "signature": { "name": "signature", "display_name": "Signature", "type": "notable_event_field", "input_type": "composition", "values": [ "{signature}" ], "default_value": "default_o11y_signature" }, "vendor_severity": { "name": "vendor_severity", "display_name": "Vendor Severity", "type": "notable_event_field", "input_type": "composition", "values": [ "{vendor_severity}" ], "default_value": "OK" }, "severity_id": { "name": "severity_id", "display_name": "Severity ID", "type": "notable_event_field", "input_type": "composition", "values": [ "{severity_id}" ], "default_value": "1" }, "title": { "name": "title", "display_name": "Title", "type": "notable_event_field", "input_type": "composition", "values": [ "{signature}" ], "default_value": "default_title" }, "owner": { "name": "owner", "display_name": "Owner", "type": "notable_event_field", "input_type": "composition", "values": [ "unassigned" ], "default_value": "unassigned" }, "status": { "name": "status", "display_name": "Status", "type": "notable_event_field", "input_type": "composition", "values": [ "1" ], "default_value": "1" }, "subcomponent": { "name": "subcomponent", "display_name": "Subcomponent", "type": "notable_event_field", "input_type": "mapping_rule", "rule_type": "coalesce", "values": [ "{subcomponent}", [ "-" ] ] }, "description": { "name": "description", "display_name": "Description", "type": "notable_event_field", "input_type": "composition", "values": [ "{description}" ] }, "app": { "name": "app", "display_name": "App", "type": "notable_event_field", "input_type": "composition", "values": [ "{app}" ] }, "itsiDrilldownSearch": { "name": "itsiDrilldownSearch", "display_name": "ITSI Drilldown Search", "type": "notable_event_field", "input_type": "composition", "values": [ "{itsiDrilldownSearch}" ] }, "itsiDrilldownEarliestOffset": { "name": "itsiDrilldownEarliestOffset", "display_name": "ITSI Drilldown earliest offset", "type": "notable_event_field", "input_type": "mapping_rule", "rule_type": "coalesce", "values": [ "{itsiDrilldownEarliestOffset}", [ "-900" ] ], "default_value": "-900" }, "itsiDrilldownLatestOffset": { "name": "itsiDrilldownLatestOffset", "display_name": "ITSI Drilldown latest offset", "type": "notable_event_field", "input_type": "mapping_rule", "rule_type": "coalesce", "values": [ "{itsiDrilldownLatestOffset}", [ "900" ] ], "default_value": "900" }, "itsiDrilldownWebURL": { "name": "itsiDrilldownWebURL", "display_name": "ITSI Drilldown Website URL", "type": "notable_event_field", "input_type": "mapping_rule", "rule_type": "coalesce", "values": [ "{itsiDrilldownWebURL}", [ "https://splunk.com" ] ] } }, "association": { "entity_lookup_field": "", "service_ids": "" }, "cron_schedule": { "value": "*/5 * * * *", "type": "Basic" }, "status": "inactive", "title": "olly_default", "throttling": { "dedup_grouping_fields": [ "signature", "src", "subcomponent" ], "dedup_notable_event": False, "throttling_earliest_time": "-59m", "throttling_latest_time": "now" }, "is_out_of_the_box": 1, "_key": "olly_default" } APPDYNAMICS_CONNECTION = { "data_source": "appdynamics", "ingestion_method": { "type": "INDEXED_DATA", "value": 'index=main sourcetype=appdynamics_summary', "time_range": { "earliest": "-24h", "latest": "now" } }, "mapped_fields": { "src": { "name": "src", "display_name": "Source", "type": "source_field", "input_type": "composition", "values": [ "{src}" ], "default_value": "appdynamics" }, "signature": { "name": "signature", "display_name": "Signature", "type": "notable_event_field", "input_type": "composition", "values": [ "{signature}" ], "default_value": "default_appdynamics_signature" }, "vendor_severity": { "name": "vendor_severity", "display_name": "Vendor Severity", "type": "notable_event_field", "input_type": "composition", "values": [ "{vendor_severity}" ], "default_value": "OK" }, "severity_id": { "name": "severity_id", "display_name": "Severity ID", "type": "notable_event_field", "input_type": "composition", "values": [ "{severity_id}" ], "default_value": "1" }, "title": { "name": "title", "display_name": "Title", "type": "notable_event_field", "input_type": "composition", "values": [ "{signature}" ], "default_value": "default_title" }, "owner": { "name": "owner", "display_name": "Owner", "type": "notable_event_field", "input_type": "composition", "values": [ "unassigned" ], "default_value": "unassigned" }, "status": { "name": "status", "display_name": "Status", "type": "notable_event_field", "input_type": "composition", "values": [ "1" ], "default_value": "1" }, "subcomponent": { "name": "subcomponent", "display_name": "Subcomponent", "type": "notable_event_field", "input_type": "mapping_rule", "rule_type": "coalesce", "values": [ "{subcomponent}", [ "-" ] ] }, "description": { "name": "description", "display_name": "Description", "type": "notable_event_field", "input_type": "composition", "values": [ "{description}" ] }, "app": { "name": "app", "display_name": "App", "type": "notable_event_field", "input_type": "composition", "values": [ "{app}" ] }, "itsiDrilldownSearch": { "name": "itsiDrilldownSearch", "display_name": "ITSI Drilldown Search", "type": "notable_event_field", "input_type": "composition", "values": [ "{itsiDrilldownSearch}" ] }, "itsiDrilldownEarliestOffset": { "name": "itsiDrilldownEarliestOffset", "display_name": "ITSI Drilldown earliest offset", "type": "notable_event_field", "input_type": "mapping_rule", "rule_type": "coalesce", "values": [ "{itsiDrilldownEarliestOffset}", [ "-900" ] ], "default_value": "-900" }, "itsiDrilldownLatestOffset": { "name": "itsiDrilldownLatestOffset", "display_name": "ITSI Drilldown latest offset", "type": "notable_event_field", "input_type": "mapping_rule", "rule_type": "coalesce", "values": [ "{itsiDrilldownLatestOffset}", [ "900" ] ], "default_value": "900" }, "itsiDrilldownWebURL": { "name": "itsiDrilldownWebURL", "display_name": "ITSI Drilldown Website URL", "type": "notable_event_field", "input_type": "mapping_rule", "rule_type": "coalesce", "values": [ "{itsiDrilldownURI}", "{itsiDrilldownWebURL}", [ "https://splunk.com" ] ] } }, "association": { "entity_lookup_field": "", "service_ids": "" }, "cron_schedule": { "value": "*/5 * * * *", "type": "Basic" }, "status": "inactive", "title": "appdynamics_default", "throttling": { "dedup_grouping_fields": [ "signature", "src", "subcomponent" ], "dedup_notable_event": False, "throttling_earliest_time": "-59m", "throttling_latest_time": "now" }, "is_out_of_the_box": 1, "_key": "appdynamics_default", } THOUSANDEYES_CONNECTION = { "data_source": "thousandeyes", "ingestion_method": { "type": "INDEXED_DATA", "value": 'index=main sourcetype=thousandeyes_summary', "time_range": { "earliest": "-24h", "latest": "now" } }, "mapped_fields": { "src": { "name": "src", "display_name": "Source", "type": "source_field", "input_type": "composition", "values": [ "{src}" ], "default_value": "thousandeyes" }, "signature": { "name": "signature", "display_name": "Signature", "type": "notable_event_field", "input_type": "composition", "values": [ "{signature}" ], "default_value": "default_thousandeyes_signature" }, "vendor_severity": { "name": "vendor_severity", "display_name": "Vendor Severity", "type": "notable_event_field", "input_type": "composition", "values": [ "{vendor_severity}" ], "default_value": "OK" }, "severity_id": { "name": "severity_id", "display_name": "Severity ID", "type": "notable_event_field", "input_type": "composition", "values": [ "{severity_id}" ], "default_value": "1" }, "title": { "name": "title", "display_name": "Title", "type": "notable_event_field", "input_type": "composition", "values": [ "{signature}" ], "default_value": "default_title" }, "owner": { "name": "owner", "display_name": "Owner", "type": "notable_event_field", "input_type": "composition", "values": [ "unassigned" ], "default_value": "unassigned" }, "status": { "name": "status", "display_name": "Status", "type": "notable_event_field", "input_type": "composition", "values": [ "1" ], "default_value": "1" }, "subcomponent": { "name": "subcomponent", "display_name": "Subcomponent", "type": "notable_event_field", "input_type": "mapping_rule", "rule_type": "coalesce", "values": [ "{subcomponent}", [ "-" ] ] }, "description": { "name": "description", "display_name": "Description", "type": "notable_event_field", "input_type": "composition", "values": [ "{description}" ] }, "app": { "name": "app", "display_name": "App", "type": "notable_event_field", "input_type": "composition", "values": [ "{app}" ] }, "itsiDrilldownSearch": { "name": "itsiDrilldownSearch", "display_name": "ITSI Drilldown Search", "type": "notable_event_field", "input_type": "composition", "values": [ "{itsiDrilldownSearch}" ] }, "itsiDrilldownEarliestOffset": { "name": "itsiDrilldownEarliestOffset", "display_name": "ITSI Drilldown earliest offset", "type": "notable_event_field", "input_type": "mapping_rule", "rule_type": "coalesce", "values": [ "{itsiDrilldownEarliestOffset}", [ "-900" ] ], "default_value": "-900" }, "itsiDrilldownLatestOffset": { "name": "itsiDrilldownLatestOffset", "display_name": "ITSI Drilldown latest offset", "type": "notable_event_field", "input_type": "mapping_rule", "rule_type": "coalesce", "values": [ "{itsiDrilldownLatestOffset}", [ "900" ] ], "default_value": "900" }, "itsiDrilldownWebURL": { "name": "itsiDrilldownWebURL", "display_name": "ITSI Drilldown Website URL", "type": "notable_event_field", "input_type": "mapping_rule", "rule_type": "coalesce", "values": [ "{itsiDrilldownURI}", "{itsiDrilldownWebURL}", [ "https://splunk.com" ] ] } }, "association": { "entity_lookup_field": "", "service_ids": "" }, "cron_schedule": { "value": "*/5 * * * *", "type": "Basic" }, "status": "inactive", "title": "thousandeyes_default", "throttling": { "dedup_grouping_fields": [ "signature", "src", "subcomponent" ], "dedup_notable_event": False, "throttling_earliest_time": "-59m", "throttling_latest_time": "now" }, "is_out_of_the_box": 1, "_key": "thousandeyes_default", } def __init__(self, session_key, logger=None): if not isinstance(session_key, itsi_py3.string_type): raise TypeError('Invalid session key.') self.session_key = session_key self.logger = logger if logger is not None else itsi_logger self.data_integration = ItsiDataIntegration(session_key, title_validation_required=True) self.olly_connection_payload = self.OLLY_CONNECTION self.appdynamics_connection_payload = self.APPDYNAMICS_CONNECTION self.thousandeyes_connection_payload = self.THOUSANDEYES_CONNECTION def create_connection(self, _id, connection_payload): if not self.data_integration.storage_interface.wait_for_storage_init(self.session_key): raise Exception('KV store failed to initialize in time.') # Check if the connection already exists try: result = self.data_integration.get(_id) self.logger.info('Fetched data integration connection: %s. result=%s' % (_id, result)) if result: self.logger.info('Data integration connection already exists: %s' % _id) return True except ResourceNotFound: self.logger.info('Data integration connection %s does not exist. This is expected ' 'when ITSI is first installed. Will create it.' % _id) # Create the connection try: resp = self.data_integration.create(json.loads(connection_payload)) self.logger.info('resp for creating connection: %s', resp) return True except Exception as e: self.logger.exception(e) self.logger.error('Encountered exception when creating connection: %d. Exception: %s', _id, e) return False return False def create_default_data_integration_connections(self): self.logger.info('About to create default data integration connections') olly_connection_str = json.dumps(self.olly_connection_payload) appd_connection_str = json.dumps(self.appdynamics_connection_payload) thousandeyes_connection_str = json.dumps(self.thousandeyes_connection_payload) try: olly_connection = self.create_connection('olly_default', olly_connection_str) except Exception as e: self.logger.error("Unable to create olly_default connection: %s", e) try: appd_connection = self.create_connection('appdynamics_default', appd_connection_str) except Exception as e: self.logger.error("Unable to create appdynamics_default connection: %s", e) try: thousandeyes_connection = self.create_connection('thousandeyes_default', thousandeyes_connection_str) except Exception as e: self.logger.error("Unable to create thousandeyes_default connection: %s", e) return olly_connection and appd_connection and thousandeyes_connection