# Copyright (C) 2005-2025 Splunk Inc. All Rights Reserved. import json import traceback import http.client import itsi_py3 # noqa import splunk.rest as rest from ITOA.setup_logging import getLogger from ITOA.saved_search_utility import SavedSearch from ITOA.storage.itoa_storage import ITOAStorage from itsi.itsi_utils import SplunkMessageHandler from splunk.clilib.bundle_paths import make_splunkhome_path import urllib.parse import platform import subprocess import sys 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'])) from SA_ITOA_app_common.solnlib.conf_manager import ConfManager class ItsiEventGrouping(object): def __init__(self, session_key, features): self.logger = getLogger(logger_name='itsi.feature_flagging.UIViewAccessEnforcer') self.session_key = session_key self.features = features self.RULE_ENGINE_MESSAGE_ID = 'RULE_ENGINE_MESSAGE_ID' self.rules_engine_saved_search = SavedSearch.get_search( self.session_key, 'itsi_event_grouping') self.EVENT_GROUPING_URL = '/saved/searches/itsi_event_grouping?output_mode=json' self.EVENTGROUP_COLLECTION = "/servicesNS/nobody/SA-ITOA/storage/collections/data/itsi_event_grouping_status/" self.EVENT_GROUPING_OBJECT_URL = self.EVENTGROUP_COLLECTION + "itsi_event_grouping" def manage_disable_or_enable(self): if (self.features.get('itsi_event_grouping')): if self._check_kv_store_value(): self._enable_rule_engine() self._set_itsi_event_grouping_flag_status(False) self._delete_message_for_rule_engine_state() else: try: response, contents = rest.simpleRequest( path=self.EVENT_GROUPING_URL, sessionKey=self.session_key) data = json.loads(contents) disabled = data['entry'][0]["content"]['disabled'] if not disabled: self._generate_message_for_rule_engine_state() self._disable_rule_engine() if not self._check_kv_store_value(): self._set_itsi_event_grouping_flag_status(True) except Exception: self.logger.error("Failed to accesss EVENT_GROUPING_URL {}".format(traceback.format_exc())) raise def _disable_rule_engine(self): try: self.rules_engine_saved_search['disabled'] = 1 SavedSearch.save_entity(self.session_key, self.rules_engine_saved_search) self.logger.info("Rule engine disabled") except Exception: self.logger.error("Failed to disable rule engine: {}".format(traceback.format_exc())) raise def _enable_rule_engine(self): try: self.rules_engine_saved_search['disabled'] = 0 SavedSearch.save_entity(self.session_key, self.rules_engine_saved_search) self.logger.info("Rule engine enabled") except Exception: self.logger.error("Failed to enable rule engine: {}".format(traceback.format_exc())) raise def _check_itsi_event_grouping_flag_status(self): try: response, contents = rest.simpleRequest( path=self.EVENT_GROUPING_OBJECT_URL, sessionKey=self.session_key) contents = json.loads(contents) return contents["itsi_event_grouping_flag_value"] except Exception: self.logger.error("Unable to check itsi_event_grouping_flag_value flag \ status from api : {}".format(traceback.format_exc())) raise def manage_nats_server(self): cfm = ConfManager(self.session_key, 'SA-ITOA') conf = cfm.get_conf('itsi_nats') settings = conf.get('nats_settings') suite_license_check = int(settings.get('require_license', 1)) if suite_license_check == 1: nats_command = make_splunkhome_path(['etc', 'apps', 'SA-ITOA', 'bin', 'nats', 'nats-server']) if platform.system().lower() == 'windows': nats_command += '.exe' if not (self.features.get('itsi_event_grouping')): encoded_scripted_queue_input_name = urllib.parse.quote('$SPLUNK_HOME/etc/apps/SA-ITOA/bin/itsi_queue_re_init.py', safe='') is_queue_mode_enabled = self.is_queue_mode_enabled(self.session_key, encoded_scripted_queue_input_name) if is_queue_mode_enabled: self.logger.info("Stopping NATS server as ITSI license is missing") shutdown_cmd = [nats_command, '--signal', 'quit'] subprocess.run(shutdown_cmd) self.logger.info("Stopping Java Queue mode as ITSI license is missing") self.disable_modular_input(self.session_key, encoded_scripted_queue_input_name, '[$SPLUNK_HOME/etc/apps/SA-ITOA/bin/itsi_queue_re_init.py]') def disable_modular_input(self, session_key, input_mode, script): try: response, content = rest.simpleRequest( f"/servicesNS/nobody/SA-ITOA/data/inputs/script/{input_mode}?disabled=1", sessionKey=session_key, method="POST", raiseAllErrors=True, ) if response.status != 200: raise Exception("Error while disabling the modular input") except Exception as err: self.logger.error('Error occurred while disabling the ' + script + ' scripted input: %s', str(err)) def is_queue_mode_enabled(self, session_key, input_name): try: response, content = rest.simpleRequest( f"/servicesNS/nobody/SA-ITOA/data/inputs/script/{input_name}?output_mode=json", sessionKey=session_key, method="GET", raiseAllErrors=True, ) parsed_content = json.loads(content) if not parsed_content["entry"][0]["content"]["disabled"]: return True else: return False except Exception as e: self.logger.error('Error while validating the queue mode process : %s', str(e)) def _check_kv_store_value(self): try: if ITOAStorage().wait_for_storage_init(self.session_key): response, contents = rest.simpleRequest( path=self.EVENTGROUP_COLLECTION, sessionKey=self.session_key) contents = json.loads(contents) if not contents: response_obj, contents_obj = rest.simpleRequest( path=self.EVENTGROUP_COLLECTION, method="POST", jsonargs=json.dumps({ "itsi_event_grouping_flag_value": True, "_key": "itsi_event_grouping" }), sessionKey=self.session_key) self.logger.info("itsi_event_grouping collection found empty posted \ object with itsi_event_grouping_flag_value:{}".format(True)) return self._check_itsi_event_grouping_flag_status() except Exception: self.logger.error("Unable to add object to collection \ itsi_event_grouping_status : {}".format(traceback.format_exc())) raise def _set_itsi_event_grouping_flag_status(self, status): """ This method maintains the state of itsi_event_grouping functionality. This method sets itsi_event_grouping_flag_value to True or False on the basis of suite_state. When user is in standard suite the flag itsi_event_grouping_flag_value will set to True. When user is in Plus suite the itsi_event_grouping_flag_value value will set to False. """ response, contents = rest.simpleRequest( path=self.EVENT_GROUPING_OBJECT_URL, method="POST", jsonargs=json.dumps({"itsi_event_grouping_flag_value": status}), sessionKey=self.session_key) if response.status == http.client.OK: self.logger.info( "Itsi_event_grouping flag status set to: " + str(status)) return e = Exception( "Failed to set itsi_event_grouping status to {}. Response={}". format(status, response)) self.logger.exception(e) raise e def _generate_message_for_rule_engine_state(self): messages = SplunkMessageHandler(self.session_key) try: message_text = ( "The 'itsi_event_grouping' search is disabled for IT Essentials Work. \ Enabling the search might cause an error.") self.logger.info(message_text) messages.post_or_update_message(self.RULE_ENGINE_MESSAGE_ID, SplunkMessageHandler.INFO, message_text) except Exception: self.logger.error("unable to generate message about itsi_event_grouping status") def _delete_message_for_rule_engine_state(self): messages = SplunkMessageHandler(self.session_key) try: messages.delete_message(self.RULE_ENGINE_MESSAGE_ID) except Exception: # the message might be already deleted by user pass