Name

sn_em_arm.EvtMgmtAlertMgmtAlertReopenHandler

Description

No description available

Script

gs.include('EvtMgmtIncidentHandler');
gs.include('EvtMgmtAlertMgmtCommons');
gs.include('EvtMgmtAlertMgmtProcess');

var EvtMgmtAlertMgmtAlertReopenHandler = Class.create();
EvtMgmtAlertMgmtAlertReopenHandler.prototype = {

  type: 'EvtMgmtAlertMgmtAlertReopenHandler',

  initialize: function() {
      this.evtMgmtCommons = new global.EvtMgmtCommons();
      this.evtMgmtAlertMgmtMediator = new global.EvtMgmtAlertMgmtMediator();
      this.evtMgmtAlertMgmtCommons = new EvtMgmtAlertMgmtCommons();
      this.evtMgmtAlertMgmtProcess = new EvtMgmtAlertMgmtProcess();
  },

  onAlertReopen: function(current) {
      // This rule runs when a closed alert is reopened or goes into flapping for a new event
      // It checks if the associated task is in the resolved or closed state
      // If it is, then it can reopen that task or create a new one (checks the property alert_reopens_incident)
      // If not, it just adds a comment on the task

      var alertNumber = current.number;

      var task = new GlideRecord("task");
      task.get(current.incident);

      var type;
      var gr = new GlideRecord("em_task_type_choices");
      gr.addQuery("type", task.sys_class_name);
      gr.query();
      if (!gr.next())
          type = "task";
      else
          type = task.sys_class_name;

      if (type != "task") {
          task = new GlideRecord(type);
          task.get(current.incident);
      }

      gr.initialize();
      gr.addQuery("type", type);
      var qc = gr.addQuery("state", "2");
      qc.addOrCondition("state", "3");
      gr.query();

      var resolved, closed;
      if (gr.next())
          resolved = gr.getValue('value');
      if (gr.next())
          closed = gr.getValue('value');

      var taskNumber = task.number;
      var taskState = task.state;

      // Task is Resolved or Closed
      if (resolved == taskState || closed == taskState) {
          var property = gs.getProperty('evt_mgmt.alert_reopens_incident');

          var manualIncident = this.incidentCreatedManually(task);

          if (property == 'reopen')
              this.handleReopen(current, alertNumber, manualIncident, taskNumber, task);
          else if (property == 'new')
              this.handleNew(current, alertNumber, manualIncident, type, task, taskNumber);
          else if (property == 'nothing') {
              // do nothing
          }

      } else {
          // Incident is still open, just add a comment to it
          this.updateWorkNoteField(task, gs.getMessage("The related alert {0} state is now {1}", [alertNumber, current.state]));
          task.update();
      }
  },

  incidentCreatedManually: function(task) {
      // backdoor to disable the feature for backward support
      if ('true' == gs.getProperty('evt_mgmt.always_reopen_incident', 'false'))
          return true;

      var toReopen = false;
      var incidentCreatedByUser = "" + task.sys_created_by;
      var jobUser = this.evtMgmtAlertMgmtMediator.getIncidentCreatingJobUser();

      // manually created incidents should be opened without additional checks
      return (incidentCreatedByUser != jobUser);
  },

  createNewTaskByAlertRules: function(current) {
      // create task with admin user - to be same as the one created by job
      var jobUser = this.evtMgmtAlertMgmtMediator.getIncidentCreatingJobUser();
      var originalUser = this.evtMgmtAlertMgmtMediator.setSessionUser(jobUser);
      var createdTask = global.EvtMgmtIncidentHandler.createIncidentNoUpdate(current, true);
      this.evtMgmtAlertMgmtMediator.setSessionUser(originalUser);
      return createdTask;
  },

  updateWorkNoteField: function(gr, comments) {
      //TODO- if this is the task and not the alert, should it ne regular update???
      this.evtMgmtAlertMgmtMediator.updateWorkNotesOnAlert(gr, comments);
  },

  addWorkNoteAndClearTaskIfNeed: function(current, taskNumber) {
      var propertyIncidentClosesAert = gs.getProperty('evt_mgmt.incident_closes_alert');

      if (propertyIncidentClosesAert == 'true') {
          // cleanup the incident - no matching alert rule and it is not manual created incident
          // we should clear it to avoid inconsistent situation
          // when opened alert has closed incident
          this.updateWorkNoteField(
              current,
              gs.getMessage("Connected incident {0} is in Resolved state while the alert is Reopend. There is no matching alert rule to reopen the incident. Disconnecting the incident from the alert.", [taskNumber]));
          current.incident = "";
      } else {
          this.updateWorkNoteField(
              current,
              gs.getMessage("Connected incident {0} is in Resolved state while the alert is Reopend. There is no matching alert rule to reopen the incident.", [taskNumber]));
      }

      this.evtMgmtAlertMgmtMediator.currentUpdateWithoutRecursiveCalls(current);

  },

  reopen: function(current, taskNumber, task) {
      // Reopen incident
      task.state = '1'; // New state
      this.updateWorkNoteField(task, gs.getMessage("The related alert {0} state is now {1}", [current.number, current.state]));
      task.state = '1';
      task.update();
  },

  getAlertManagementExecutionByAlert: function(alertGR) {

      //Using Alert rules management
      if (gs.getProperty('evt_mgmt.alert.management.activated', false) === 'true') {

          //Worng input, can't find esecution
          if ((!alertGR) || (!alertGR.getUniqueValue()) || (!alertGR.incident))
              return null;

          var executionGR = new GlideRecord("em_alert_management_execution");
          executionGR.addQuery('alert', alertGR.getUniqueValue());
          executionGR.addQuery('related_task', alertGR.incident);
          executionGR.orderByDesc('sys_created_on');
          executionGR.setLimit(1);
          executionGR.query();
          if (executionGR.next()) {
              return executionGR;
          }
      }
      return null;
  },

  isManualExecution: function(manualIncidentByUserID, amExecutionGR) {

      // backdoor to disable the feature for backward support
      if ('true' == gs.getProperty('evt_mgmt.always_reopen_incident', 'false'))
          return true;

      if (amExecutionGR == null) {
          //No execution- treat like legacy
          return manualIncidentByUserID;
      } else {
          //there is an am execution, make sure it's marked as manual
          return amExecutionGR.automatic_run == "0";
      }
  },

  alertMatchеsAlertManagementRules: function(alertGR, executionGR) {

      //Using Alert rules management
      if (gs.getProperty('evt_mgmt.alert.management.activated', false) === 'true') {

          if (executionGR != null) { //no execution, should treat like legacy alert

              var rule = this.evtMgmtAlertMgmtCommons.getRuleFromCacheByID(executionGR.management_rule);

              if (this.alertMatchesRuleFilterNoInt(alertGR, rule)) {
                  return true;
              } else {
                  return false;
              }
          }
      }

      return this.alertMatchеsLegacyRules(alertGR);
  },

  /**
  	Checks rather alert matches the rule's filter- remove the int before doing that...
  */
  alertMatchesRuleFilterNoInt: function(alertGR, rule) {
      var oldTask = alertGR.incident + "";
      alertGR.incident = "";
      var filterRes = this.evtMgmtAlertMgmtProcess.checkFilter(alertGR, rule);
      alertGR.incident = oldTask;
      return filterRes;
  },

  alertMatchеsLegacyRules: function(alert) {
      if (gs.getProperty('evt_mgmt.alert.management.enable_legacy_alert_action_rules', 'true') == 'true') { // if property is turned on, used to disable legacy alert rules where not needed

          // automatically created incidents should be opened only if the alert match alert rules
          var rule = global.EvtMgmtIncidentHandler.locateRule(alert, true);
          return (rule != null);
      }
      return false;
  },

  handleReopen: function(current, alertNumber, manualIncidentByUserID, taskNumber, task) {
      // if alert rules are matched or the incedent was created manually,
      // Reopen incident

      var amExecutionGR = this.getAlertManagementExecutionByAlert(current);

      if (this.isManualExecution(manualIncidentByUserID, amExecutionGR)) {
          this.reopen(current, taskNumber, task);
      } else {

          var ruleMatched = this.alertMatchеsAlertManagementRules(current, amExecutionGR);
          if (ruleMatched) {
              this.reopen(current, taskNumber, task);
          } else {
              // no matched rule, and incident was created by Job,
              // the incident should not be reopened
              this.addWorkNoteAndClearTaskIfNeed(current, taskNumber);
          }
      }
  },

  createNew: function(current, alertNumber, newTask, taskNumber, type, task) {
      // Create a new one and copy fields from the old one here
      newTask.initialize();

      // Copy all fields into newIncident
      var fields = task.getElements();
      var fieldsToIgnore = gs.getProperty('evt_mgmt.open_new_incident_ignore_fields', 'number,state,opened_at');
      fieldsToIgnore = fieldsToIgnore.replace(/ /g, ''); //remove all spaces
      var fieldsToIgnoreArr = JSON.stringify(fieldsToIgnore.split(","));

      for (var i = 0; i < fields.length; ++i) {
          var ele = fields[i];
  		if ((typeof ele.getName() == "undefined") ||ele.getName() == "active"|| (((ele.getName() +"").startsWith("sys_")) && (!((ele.getName() +"").startsWith("sys_domain")))) || fieldsToIgnoreArr.includes(ele.getName())){
  			continue;
          }
          newTask.setValue(ele.getName(), ele);
      }
      // Add comments on new incident
      this.updateWorkNoteField(newTask, gs.getMessage("The related alert {0} is now unlinked from the previous {1} {2}", [alertNumber, type, taskNumber]));
      newTaskId = newTask.insert();
      current.incident = newTaskId;
  },

  handleNew: function(current, alertNumber, manualIncidentByUserID, type, task, taskNumber) {

      // Create a new task and update comments on the task
      // about the alert's previous task being unlinked
      var newTaskId;
      var newTask = new GlideRecord(type);
      var createdTask;

      var amExecutionGR = this.getAlertManagementExecutionByAlert(current);

      if (this.isManualExecution(manualIncidentByUserID, amExecutionGR)) {
          // Create a new one and copy fields from the old one here
          this.createNew(current, alertNumber, newTask, taskNumber, type, task);
          createdTask = true;
      } else {

          if (amExecutionGR != null) { //int was created by an AM rule, we just remove the int field and let the job do the logic
              createdTask = false;
              this.updateWorkNoteField(task, gs.getMessage("The related alert {0} is now unlinked from the {1} {2}", [alertNumber, type, taskNumber]));
              task.update();
              this.updateWorkNoteField(current, gs.getMessage("Connected incident {0} is in Resolved state while the alert is Reopend. Disconnecting the incident from the alert.", [taskNumber]));
              current.incident = "";
              this.evtMgmtAlertMgmtMediator.currentUpdateWithoutRecursiveCalls(current);
          } else {

              createdTask = this.createNewTaskByAlertRules(current);

              if (createdTask) {
                  // found matching alert rule and task was created
                  newTaskId = current.incident;
                  newTask.get(newTaskId);
                  // Add comments on new incident
                  this.updateWorkNoteField(newTask, gs.getMessage("The related alert {0} is now unlinked from the previous {1} {2}",
                      [alertNumber, type, taskNumber]));
                  newTask.update();
              } else {
                  // no matched rule, and incident was created by Job, so the incident should not be reopened
                  this.addWorkNoteAndClearTaskIfNeed(current, taskNumber);
              }
          }

      }

      if (createdTask) {
          var newTaskNumber = newTask.number;

          // Add comments on old incident
          this.updateWorkNoteField(task, gs.getMessage("The related alert {0} is now linked to a new {1} {2}", [alertNumber, type, newTaskNumber]));
          task.update();

          // Add comments on alert
          this.updateWorkNoteField(current, gs.getMessage("The {0} number changed from {1} to {2}", [type, taskNumber, newTaskNumber]));
          this.evtMgmtAlertMgmtMediator.currentUpdateWithoutRecursiveCalls(current);
      }

  },

};

Sys ID

8ff399e6b7d920107c038229ce11a9cc

Offical Documentation

Official Docs: