Name
sn_em_arm.EvtMgmtAlertMgmtProcess
Description
No description available
Script
gs.include('EvtMgmtCommons');
gs.include('EvtMgmtAlertMgmtCommons');
gs.include('SlowStepJSManager');
var EvtMgmtAlertMgmtProcess = Class.create();
EvtMgmtAlertMgmtProcess.prototype = {
type: 'EvtMgmtAlertMgmtProcess',
initialize: function(pSlowStepJSManager) {
this.WORKFLOW_LINK = "/context_workflow.do?sysparm_sys_id=";
this.SUBFLOW_LINK = "/$flow-designer.do?sysparm_nostack=true#/operations/context/";
this.SUBFLOW_WRAPPER = 'sn_em_arm.arm_callback_wrapper';
this.evtMgmtCommons = new global.EvtMgmtCommons();
this.evtMgmtAlertMgmtMediator = new global.EvtMgmtAlertMgmtMediator();
this.slowStepsManager = pSlowStepJSManager;
this.evtMgmtAlertMgmtCommons = new EvtMgmtAlertMgmtCommons();
this.evtMgmtAlertMgmtToolBox = new EvtMgmtAlertMgmtToolBox();
this.fRuleAdditionalInfo = {};
this.fApplicationServicesPerCI = {};
this.enableSynchronousSubflow = gs.getProperty("evt_mgmt.alert.management.enable_synchronous_subflow", 'false') == 'true';
//constants:
this.ADDITIONAL_INFO_TABLE = "sn_em_arm_additional_info";
this.IMPACT_GRAPH_TABLE = "em_impact_graph";
this.ALERT_MGMT_RULE = "alert_management_rule";
this.SCRIPT_CONDITION = "condition_script";
this.USE_SCRIPT = "use_script_condition";
this.DEPENDENT_ON_RULE = "dependent_on_rule";
this.ALERT_KEY_FIELD = "alert_key_field";
this.ALERT_KEY_VALUE = "alert_key_value";
this.IS_ADD_INFO_FIELD = "is_add_info_field";
this.ALERT_ADDITIONAL_INFO = "additional_info";
this.ALERT_KEY_IDENTIFIER_FIELD = gs.getProperty("sn_em_arm.alert_key_identifier_add_info_field", 'sn_integration_id');
this.QUERY_IMPACT_GRAPH = gs.getProperty("sn_em_arm.evt_mgmt.query_impact_graph", 'true');
this.MAX_APP_PER_CI = gs.getProperty("sn_em_arm.evt_mgmt.max_application_for_ci", 100);
this.SYS_ID = "sys_id";
this.CMDB_CI = "cmdb_ci";
this.BUSINESS_SERVICE = "business_service";
this.APPLIES_TO = "applies_to";
this.APPLIES_TO_NONE = "none";
this.APPLIES_TO_SERVICE = "service";
this.APPLIES_TO_CI = "ci";
this.APPLIES_TO_BOTH = "both";
this.CHILD = "child_id";
this.STATUS = "status";
},
runForAlert: function(alertGR, returnToPreviousDomain, manuallyRun, retrieveParams, executionsMap, perfCounters) {
this.startStep(this.type + ": runForAlert- Handle domain");
var originalDomain = this.evtMgmtCommons.getCurrentDomainID();
this.evtMgmtCommons.changeDomain(this.evtMgmtCommons.getRecordDomain(alertGR));
this.startStep(this.type + ": getReleveantAlertRules");
var relevantRules = this.evtMgmtAlertMgmtMediator.getReleveantAlertRules();
//sending one alert and the relevant rules for the this alert
var manuallyActions = this.iterateOverRules(alertGR, relevantRules, manuallyRun, retrieveParams, executionsMap, perfCounters, false);
this.startStep(this.type + ": runForAlert- returnToPreviousDomain");
if (returnToPreviousDomain) {
this.evtMgmtCommons.changeDomain(originalDomain);
}
this.startStep(this.type + ": end of runForAlert");
return manuallyActions;
},
iterateOverRules: function(alertGR, ruleList, manuallyRun, retrieveParams, executionsMap, perfCounters, runDependentRules) {
var lastExecutionGR = null;
var lastSysId = [];
var shouldExecuteActions = true;
var result = {
remediations: [],
launchApplications: [],
subflows: []
};
var ruleAdditionalInfo = this.loadAdditionalInfo(ruleList);
var ruleAddInfoMap = ruleAdditionalInfo.ruleDataMap;
var passthroughParams = JSON.stringify({
retrieveParams: retrieveParams
});
var ruleAddInfoMapIsEmpty = this.evtMgmtAlertMgmtToolBox.isEmptyObject(ruleAddInfoMap);
this.startStep(this.type + ": Iterate Over Rules");
// check if this alert is a SRO alert
var additionalInfo = alertGR.getValue(this.ALERT_ADDITIONAL_INFO);
var additionalInfoJSON = this.getAddInfoFieldJsonForSRO(additionalInfo);
var isSroAlert = this.isSroAlert(additionalInfoJSON);
// Save the number of SRO alerts to sa_performance_statistics
if (perfCounters) {
perfCounters.sroAlertsCount += Number(isSroAlert) || 0;
}
for (var i = 0; i < ruleList.length; i++) {
try {
var rule = ruleList[i];
var ruleSysId = rule.getSysId();
var thisRuleInfo = ruleAddInfoMap[ruleSysId];
if (!runDependentRules && !manuallyRun && thisRuleInfo && !gs.nil(thisRuleInfo.dependentOnRule) &&
this.hasActiveAncestor(ruleAdditionalInfo, thisRuleInfo.dependentOnRule)) {
// this is a dependent rule, and we're not running dependent rules now, unless all its ancestors are marked inactive
continue;
}
//reading the alert key field and value
var keyField = thisRuleInfo ? thisRuleInfo["alertKeyField"] : undefined;
var keyValue = undefined;
var keyAppliesTo = undefined;
var runTheRule = true;
if (isSroAlert) {
if (ruleAddInfoMapIsEmpty)
break; // ruleAddInfoMap is empty, SRO alert can't run any regular rules, exiting rules loop
if (!keyField) // SRO alert can't run regular rule or even its dependencies, so move on to the next rule
continue;
}
if (thisRuleInfo) {
keyAppliesTo = thisRuleInfo["alertKeyAppliesTo"];
if (keyField) // the rule has a defined key field
keyValue = thisRuleInfo["alertKeyValue"];
runTheRule = this.matchAlertKeyValue(alertGR, thisRuleInfo, keyField, keyValue, keyAppliesTo, additionalInfoJSON);
}
// if there's an entry in the map for this rule, then it has dependencies
var hasDependentRules = ruleAdditionalInfo.dependencyMap[ruleSysId];
if (runTheRule) // the alert does not impact the rule AS
{
this.startStep(this.type + ": shouldRunRule");
if (this.shouldRunRule(alertGR, rule, manuallyRun)) {
this.startStep(this.type + ": getActions");
var ruleActions = this.getActions(rule, manuallyRun, retrieveParams, executionsMap, alertGR.sys_id);
this.startStep(this.type + ": getActionsNums");
var actionsNumber = ruleActions.remediations.length + ruleActions.subflows.length + ruleActions.launchApplications.length;
if (actionsNumber == 0) {
this.evtMgmtCommons.addDebugMessage("There are no actions to run, for " + this.getDebugPrefixMessage(alertGR, rule) + ".");
// no actions to execute, but still need to check stop processing other rules flag
if (this.continueToOtherRules(rule)) {
// we do not do a callback in this situation, even if there are dependent rules, because it is possible for a race condition to cause a bug.
continue;
}
// need to proceed to check filter of this rule since stop processing other rules flag is on
}
this.startStep(this.type + ": checkFilter");
if (this.checkFilter(alertGR, rule, ruleAddInfoMap, perfCounters)) {
this.startStep(this.type + ": FilterMatched");
//If there are no valid actions, just check the continueToOtherRules flag
if (actionsNumber != 0) {
if (manuallyRun) {
this.startStep(this.type + ": union Results And Transform To Manual");
this.unionResultsAndTransformToManual(result, ruleActions, alertGR);
} else {
shouldExecuteActions = true;
lastSysId = [];
if (rule.runOnSelectiveUpdate()) {
this.startStep(this.type + ": Did Last Alert Update Matched Filter");
if (this.didLastAlertUpdateMatchedFilter(alertGR.sys_id, ruleSysId, executionsMap, lastSysId)) {
shouldExecuteActions = false; //don't executeActions until last run doesn't fit
this.evtMgmtCommons.addDebugMessage("Not running actions for " + this.getDebugPrefixMessage(alertGR, rule) + ", rule is set to selective updates.");
}
}
if (shouldExecuteActions) {
this.startStep(this.type + ": Execute Actions");
this.executeActions(alertGR, rule, ruleActions, false, hasDependentRules, passthroughParams);
if (perfCounters) {
perfCounters.remediationsCount += ruleActions.remediations.length;
perfCounters.subFlowsCount += ruleActions.subflows.length;
}
}
}
}
// check if we should stop processing other rules
if (!this.continueToOtherRules(rule)) {
break;
}
} else { // rule filter condition is false.
lastSysId = [];
if (rule.runOnSelectiveUpdate()) {
if (this.didLastAlertUpdateMatchedFilter(alertGR.sys_id, ruleSysId, executionsMap, lastSysId)) {
this.startStep(this.type + ": update Execution Filter Matches False");
this.updateExecutionFilterMatchesFalse(lastSysId[0]);
this.evtMgmtCommons.addDebugMessage("Setting last filter match to false for " + this.getDebugPrefixMessage(alertGR, rule) + ", rule is set to selective updates.");
} else {
this.evtMgmtCommons.addDebugMessage("Not setting last filter match to false since it is already false. For " + this.getDebugPrefixMessage(alertGR, rule) + ", rule is set to selective updates.");
}
}
// check for dependent rules that we may need to run, even though our condition didn't match
if (!manuallyRun && hasDependentRules) {
this.onRuleComplete(alertGR, ruleSysId, passthroughParams);
}
}
} else { // if (!this.shouldRunRule(alertGR, rule, manuallyRun))
// even if this rule does not have automatic actions, there may have been other automatic actions (erroneously?) set up as dependent on this rule
// In this case we should run the dependent actions
if (!manuallyRun && hasDependentRules) {
this.onRuleComplete(alertGR, ruleSysId, passthroughParams);
}
}
} else {
if (hasDependentRules) { //This rule did not match but we need to see if the dependent rules match
this.onRuleComplete(alertGR, ruleSysId, passthroughParams);
}
}
} catch (e) {
gs.error("Alert Management - Fail to process rule " + rule.getName() + " Alert: " + alertGR.number + "( " + alertGR.sys_id + ") " + " Error Message: " + this.evtMgmtCommons.getExceptionMessage(e, true));
}
this.startStep(this.type + ": Finished Iterate Over Rule");
}
return result;
},
hasActiveAncestor: function(ruleAdditionalInfo, alertRuleId) {
this.startStep(this.type + ": hasActiveAncestor (recursive function)");
// checks if the specified rule is active. If not, recurse through its dependency ancestors
if (ruleAdditionalInfo.activeRuleMap.hasOwnProperty(alertRuleId)) {
return true;
}
// is this rule dependent on another rule? If so, recurse
var thisRuleAddInfo = ruleAdditionalInfo.ruleDataMap[alertRuleId];
if (thisRuleAddInfo && !gs.nil(thisRuleAddInfo.dependentOnRule)) {
return this.hasActiveAncestor(ruleAdditionalInfo, thisRuleAddInfo.dependentOnRule);
}
// I am inactive, and I have no dependency ancestors, so:
return false;
},
unionResultsAndTransformToManual: function(result, ruleActions, alertGR) {
result.remediations = this.unionArrays(result.remediations, ruleActions.remediations);
result.launchApplications = this.unionArrays(result.launchApplications, this.addAlertDetailsToLaunch(ruleActions.launchApplications, alertGR));
result.subflows = this.unionArrays(result.subflows, ruleActions.subflows);
},
unionArrays: function(unionedActions, ruleActions) {
if ((ruleActions) && (ruleActions.length > 0)) {
if ((unionedActions) && (unionedActions.length > 0)) {
for (i = 0; i < ruleActions.length; i++) {
unionedActions.push(ruleActions[i]);
}
return unionedActions;
} else {
return ruleActions; //no need to copy original is empty...
}
} else { //nothing todo
return unionedActions;
}
},
addAlertDetailsToLaunch: function(launchApplications, alertGR) {
if ((launchApplications) && (launchApplications.length > 0)) {
return this.evtMgmtAlertMgmtMediator.parseURLForTools(alertGR, launchApplications);
}
return launchApplications;
},
continueToOtherRules: function(rule) {
return rule.searchAdditionalRules();
},
shouldRunRule: function(alertGR, rule, manuallyRun) {
if (manuallyRun) {
if (!rule.hasManualActions()) {
return false;
}
} else {
if (!rule.hasAutomaticActions()) {
return false;
}
}
return true;
//run once check should go here as well
},
checkFilter: function(alertGR, rule, ruleAddInfoMap, perfCounters) {
try {
var alertFilter = rule.getAlertFilter();
var returnValue = false;
this.startStep(this.type + ': checkFilter - GlideFilter() call');
// Take time before GlideFilter
var t1 = new Date();
// A mediator function calling GlideFilter.checkRecord() was added to evtMgmtAlertMgmtMediator in Tokyo,
// to fix the "trend" condition not working in scoped app. Check if the function exists before calling it.
var useMediatorToCheckFilter = typeof this.evtMgmtAlertMgmtMediator.checkRecord == 'function' ;
var isRuleGlideFilterMatch = useMediatorToCheckFilter ? this.evtMgmtAlertMgmtMediator.checkRecord(alertGR, alertFilter) :
GlideFilter.checkRecord(alertGR, alertFilter);
var t2 = new Date(); // Take time after GlideFilter and before evaluateRuleScript
var t3; // init var for taking time after evaluateRuleScript
//we want to evaluate the script if exists only if the filter matches
if (isRuleGlideFilterMatch) {
this.startStep(this.type + ': checkFilter - evaluateRuleScript() call');
returnValue = this.evaluateRuleScript(rule, ruleAddInfoMap, alertGR);
t3 = new Date(); // take time before evaluateRuleScript
}
this.startStep(this.type + ': end checkFilter');
if (perfCounters) {
// Keep the max run time, related alert and rule name for getAlertFilter
if (t2 - t1 >= perfCounters.maxDurationGlideFilterRule.value) {
perfCounters.maxDurationGlideFilterRule.value = t2 - t1;
perfCounters.maxDurationGlideFilterRule.alert = alertGR.getValue('number');
perfCounters.maxDurationGlideFilterRule.ruleName = rule.getName();
}
// Keep the max run time, related alert and rule name for evaluateRuleScript
if (t3 && (t3 - t2 >= perfCounters.maxDurationEvaluateRuleScript.value)) {
perfCounters.maxDurationEvaluateRuleScript.value = t3 - t2;
perfCounters.maxDurationEvaluateRuleScript.alert = alertGR.getValue('number');
perfCounters.maxDurationEvaluateRuleScript.ruleName = rule.getName();
}
}
return returnValue;
} catch (e) {
gs.error("Alert management rule: " + rule.getName() + " has invalid filter/script filter: " + alertFilter + ". Error is: " + this.evtMgmtCommons.getExceptionMessage(e, true));
return false;
}
},
getActions: function(rule, manuallyRun, retrieveParams, executionsMap, alertSysId) {
var actions = {
remediations: [],
launchApplications: [],
subflows: []
};
if (retrieveParams.retrieveRemediations) {
actions.remediations = this.getRemediations(rule, manuallyRun, executionsMap, alertSysId);
}
if (retrieveParams.retrieveLaunchApplications) {
actions.launchApplications = this.getLaunchApplications(rule, manuallyRun);
}
if (retrieveParams.retrieveSubflows) {
actions.subflows = this.getSubflows(rule, manuallyRun, executionsMap, alertSysId);
}
return actions;
},
getRemediations: function(rule, manuallyRun, executionsMap, alertSysId) {
//rule.getRemediations function expects automatic flag
this.startStep(this.type + ": getActions - getRemediations");
var ruleRemediations = rule.getRemediations(!manuallyRun);
this.startStep(this.type + ": getActions - checkLimits");
var remediations = this.checkLimits(rule, manuallyRun, executionsMap, alertSysId, ruleRemediations);
return remediations;
},
// filter out actions which reached their limits
checkLimits: function(rule, manuallyRun, executionsMap, alertSysId, actions) {
var actionObjects = [];
var actionCounters = this.getActionCounters(rule.getSysId(), executionsMap, alertSysId);
var actionsExist = this.evtMgmtAlertMgmtToolBox.isNotEmpty(actionCounters);
var numOfExecutionsTillNow = 0; // assume first run unless told otherwise
//it's required to convert the native array to js array
for (var i = 0; i < actions.length; i++) {
if (!manuallyRun) {
var limit = actions[i].getExecutionsLimit();
if (actionsExist) {
var action = actions[i];
var actionSysId = action.getActionSysid();
numOfExecutionsTillNow = actionCounters[actionSysId];
if (numOfExecutionsTillNow) {
if (numOfExecutionsTillNow >= limit) {
continue;
}
} else {
numOfExecutionsTillNow = 0; // first run
}
} else {
numOfExecutionsTillNow = 0; // assume first run unless told otherwise
}
}
// TODO: remove rule field (we have it already in action field)
actionObjects.push({
action: actions[i],
numOfExecutions: Number(numOfExecutionsTillNow) + 1,
rule: rule.getSysId(),
ruleOrder: rule.getOrder(),
ruleName: rule.getName()
});
}
return actionObjects;
},
getActionCounters: function(ruleSysId, executionsMap, alertSysId) {
var key = this.evtMgmtAlertMgmtCommons.createKeyWithRuleAndAlert(alertSysId, ruleSysId);
return executionsMap && executionsMap[key] ? executionsMap[key] : null;
},
getLaunchApplications: function(rule, manuallyRun) {
var launchApplications = [];
this.startStep(this.type + ": getActions - getLaunchApplications");
if (manuallyRun) { //launch applications should only be avilable for manual runs
var ruleLaunchApplications = rule.getLaunchApplications();
//it's required to convert the native array to js array
for (var i = 0; i < ruleLaunchApplications.length; i++) {
var launchObject = ruleLaunchApplications[i];
launchApplications.push(launchObject);
}
}
return launchApplications;
},
getSubflows: function(rule, manuallyRun, executionsMap, alertSysId) {
this.startStep(this.type + ": getActions - getSubflows");
var ruleSubflows = rule.getSubflows(!manuallyRun);
this.startStep(this.type + ": getActions - getSubflows - checkLimits ");
var subflows = this.checkLimits(rule, manuallyRun, executionsMap, alertSysId, ruleSubflows);
return subflows;
},
executeActions: function(alertGR, rule, actions, manuallyRun, hasDependentRules, passthroughParams) {
this.debugMessageExecuteActionsBefore(alertGR, rule, actions);
//executing remediations:
for (var i = 0; i < actions.remediations.length; i++) {
this.debugMessageExecuteActionsInRemediations(alertGR, rule, actions, i);
var remediation = actions.remediations[i];
this.executeRemediationObj(alertGR, remediation, rule, manuallyRun);
}
if (actions.subflows.length > 0) {
//executing subflows: [scopeOfSubflow].[subflowName]
for (var j = 0; j < actions.subflows.length; j++) {
// only use the callback function if this rule has dependent rules, it's not manually run,
// and this is the last subflow for this rule.
var invokeWithCallback = hasDependentRules && !manuallyRun && j == actions.subflows.length - 1;
var sendSingleAlertGr = gs.getProperty('evt_mgmt.send_single_alert_to_subflow', 'true') == 'true';
if (sendSingleAlertGr) {
var currAlertGr = new GlideRecord("em_alert");
currAlertGr.get(alertGR.sys_id);
this.executeSubflow(currAlertGr, actions.subflows[j], rule, manuallyRun, invokeWithCallback, passthroughParams);
} else {
this.executeSubflow(alertGR, actions.subflows[j], rule, manuallyRun, invokeWithCallback, passthroughParams);
}
}
}
this.debugMessageExecuteActionsAfter(alertGR, rule);
},
executeSubflowManually: function(alertSysId, actionFullName, actionName, ruleSydId, actionId) {
var alertGR = new GlideRecord('em_alert');
alertGR.get(alertSysId);
var ruleGR = new GlideRecord('em_alert_management_rule');
ruleGR.get(ruleSydId);
var contextId = this.callActivateSubflowAPI(actionFullName, ruleGR.name, ruleSydId, alertGR, true, undefined, undefined, actionId, actionName);
return contextId;
},
executeSubflow: function(alertGR, actionObject, rule, manuallyRun, invokeWithCallback, passthroughParams) {
var action = actionObject.action;
var actionFullName = action.getReferenceExecutionName();
var actionId = action.getActionSysid();
var actionName = action.getReferenceActionDisplayName();
var actionRefId = action.getReferenceActionID();
var numOfExecutions = actionObject.numOfExecutions;
var executionsLimit = actionObject.action.getExecutionsLimit();
var contextId = this.callActivateSubflowAPI(actionFullName, rule.getName(), rule.getSysId(), alertGR, manuallyRun,
numOfExecutions, executionsLimit, actionId, actionName, actionRefId, invokeWithCallback, passthroughParams);
},
callActivateSubflowAPI: function(actionFullName, ruleName, ruleSysId, alertGR, manuallyRun, numOfExecutions, executionsLimit,
actionId, actionName, actionRefId, invokeWithCallback, passthroughParams) {
var executionGR = this.createExectionRec();
var inputs = {
"ah_alertrulename": ruleName,
"ah_alertruleid": ruleSysId,
"ah_alertgr": alertGR,
"ah_executionid": executionGR.getUniqueValue(),
"ah_username": gs.getUserName(),
"ah_userdisplayname": gs.getUserDisplayName()
};
if (invokeWithCallback) {
inputs.ah_invokesubflow = actionRefId; // if we're invoking a wrapper, it's most reliable to use the subflow's id
// the following parameter is passed directly through to the callback method
inputs.ah_passthroughparams = passthroughParams;
}
try {
var contextId;
var actionToExecute = invokeWithCallback ? this.SUBFLOW_WRAPPER : actionFullName;
if (gs.getProperty("evt_mgmt.alert.management.enable_legacy_whitelist_executeSubflow", 'false') == 'true') {
contextId = this.evtMgmtAlertMgmtMediator.executeSubflow(actionToExecute, this.evtMgmtCommons.getRecordDomain(alertGR), inputs);
} else if (this.enableSynchronousSubflow) {
var startTimeForPerformence = new Date().getTime();
contextId = this.evtMgmtAlertMgmtMediator.executeSubflowSync(actionToExecute, inputs);
var duration = (new Date().getTime()) - startTimeForPerformence;
this.evtMgmtCommons.addDebugLogNoPrefix('EvtMgmtAlertMgmtProcess synchronous callActivateSubflowAPI of ' + actionFullName + ' took ' + duration + ' ms');
} else {
contextId = this.evtMgmtAlertMgmtMediator.startSubflowSkipInputValidation(actionToExecute, inputs);
}
var logMessage = "";
if (gs.nil(contextId)) {
logMessage = this.getFailureExecutingLogMessage(manuallyRun, numOfExecutions, executionsLimit, gs.getMessage("Subflow '{0}' couldn't be started.", [actionName]));
} else {
logMessage = this.getSuccessExecutingLogMessage(manuallyRun, numOfExecutions, executionsLimit);
}
this.addExecutionRunForRecord(executionGR, alertGR.sys_id, ruleSysId, manuallyRun, contextId, actionName, "", this.SUBFLOW_LINK, logMessage, actionId);
return contextId;
} catch (error) {
gs.error("Problem on running subflow " + actionFullName + " for alert " + alertGR.getUniqueValue() + ". Error is: " + this.evtMgmtCommons.getExceptionMessage(error, true));
var logMessage2 = this.getFailureExecutingLogMessage(manuallyRun, numOfExecutions, executionsLimit, gs.getMessage("Subflow '{0}' couldn't be started: {1}.", [actionFullName, error]));
this.addExecutionRunForRecord(executionGR, alertGR.sys_id, ruleSysId, manuallyRun, "", actionName, "", "", logMessage2, actionId);
}
},
//called only when its automatic
executeRemediationObj: function(alertGR, actionObject, rule, manuallyRun) {
var refActionId = actionObject.action.getReferenceActionID();
var actionName = actionObject.action.getWorkflowName();
var actionId = actionObject.action.getActionSysid();
var numOfExecutions = actionObject.numOfExecutions;
var executionsLimit = actionObject.action.getExecutionsLimit();
return this.executeRemediation(alertGR.sys_id, alertGR.cmdb_ci, rule.getSysId(), refActionId, actionName, manuallyRun, numOfExecutions, executionsLimit, actionId);
},
//called for automatic and manually
executeRemediation: function(alertSysid, cmdbCi, ruleSysId, refActionId, actionName, manuallyRun, numOfExecutions, limit, actionId) {
var taskId = this.evtMgmtAlertMgmtMediator.startRemediationReturnTaskId(alertSysid, cmdbCi, refActionId);
var contextId = this.getContextByTask(taskId);
var logMessage = "";
if (gs.nil(taskId) || gs.nil(contextId)) {
contextId = ""; //init context since it get a "null" value, not empty for worng tasks
logMessage = this.getFailureExecutingLogMessage(manuallyRun, numOfExecutions, limit, gs.getMessage("Remediation '{0}' couldn't be started.", [actionName]));
this.addExecutionRun(alertSysid, ruleSysId, manuallyRun, contextId, actionName, taskId, "", logMessage, actionId);
} else {
logMessage = this.getSuccessExecutingLogMessage(manuallyRun, numOfExecutions, limit);
this.addExecutionRun(alertSysid, ruleSysId, manuallyRun, contextId, actionName, taskId, this.WORKFLOW_LINK, logMessage, actionId);
}
return contextId;
},
getSuccessExecutingLogMessage: function(manuallyRun, numOfExecutions, limit) {
if (manuallyRun) {
return gs.getMessage('Manual execution.');
} else {
return gs.getMessage('Automatic execution #{0} out of {1}.', [numOfExecutions + "", limit + ""]);
}
},
getFailureExecutingLogMessage: function(manuallyRun, numOfExecutions, limit, failureMessage) {
if (manuallyRun) {
return gs.getMessage('Failure on manual execution. {0}', failureMessage);
} else {
return gs.getMessage('Failure on automatic execution #{0} out of {1}. {2}', [numOfExecutions + "", limit + "", failureMessage]);
}
},
getContextByTask: function(taskId) {
var gr = new GlideRecord("wf_context");
gr.addQuery("id", taskId);
gr.query();
if (gr.next())
return gr.getUniqueValue();
return null;
},
addExecutionRun: function(alertId, ruleSysId, manuallyRun, contextId, actionName, taskId, linkPrefix, log, actionId) {
return this.addExecutionRunForRecord(this.createExectionRec(), alertId, ruleSysId, manuallyRun, contextId, actionName, taskId, linkPrefix, log, actionId);
},
createExectionRec: function() {
var executions = new GlideRecord("em_alert_management_execution");
executions.setNewGuidValue(gs.generateGUID());
if (this.enableSynchronousSubflow) {
executions.insert();
}
return executions;
},
addExecutionRunForRecord: function(executions, alertId, ruleSysId, manuallyRun, contextId, actionName, taskId, linkPrefix, log, actionId) {
var update = false;
if (this.enableSynchronousSubflow) {
executions.addQuery(this.SYS_ID, executions.getValue(this.SYS_ID));
executions.query();
update = executions.next();
}
executions.management_rule = ruleSysId;
executions.alert = alertId;
executions.historical = false;
executions.automatic_run = !manuallyRun;
executions.action_name = actionName;
var task = executions.getValue('related_task');
if (!this.enableSynchronousSubflow || gs.nil(task)) {
executions.related_task = taskId;
}
executions.link = linkPrefix + contextId;
executions.log = log;
executions.rule_action = actionId;
executions.filter_always_match = true;
if (update) {
executions.update();
} else {
executions.insert();
}
},
didLastAlertUpdateMatchedFilter: function(alertId, ruleId, executionsMap, lastSysId) {
var key = this.evtMgmtAlertMgmtCommons.createKeyWithRuleAndAlert(alertId, ruleId);
var result = "false";
if (this.evtMgmtCommons.isDebugEnabled()) { //Don't json stringify if not debugging
this.evtMgmtCommons.addDebugMessage("In didLastAlertUpdateMatchedFilter Execution map is: " + JSON.stringify(executionsMap));
}
if (executionsMap) {
if (executionsMap[key]) {
result = executionsMap[key][this.evtMgmtAlertMgmtCommons.LAST_EXECUTION_FILTER_MATCH];
lastSysId[0] = executionsMap[key][this.evtMgmtAlertMgmtCommons.LAST_EXECUTION_SYS_ID];
this.evtMgmtCommons.addDebugMessage("In didLastAlertUpdateMatchedFilter() for rule " + ruleId + ", LAST_EXECUTION_FILTER_MATCH=" + result + ", LAST_EXECUTION_SYS_ID= " + lastSysId[0]);
}
}
//It's a string, not boolean so we need to check it this way
return result === "true";
},
updateExecutionFilterMatchesFalse: function(executionId) {
var executions = new GlideRecord("em_alert_management_execution");
if (executions.get(executionId)) {
executions.filter_always_match = false;
executions.update();
}
},
getSubflowName: function(subflowFullName) {
var subflowName = subflowFullName;
if (subflowFullName.indexOf(".") > -1) {
subflowName = subflowFullName.substring(subflowFullName.indexOf(".") + 1);
}
return subflowName;
},
debugMessageExecuteActionsBefore: function(alertGR, rule, actions) {
this.evtMgmtCommons.addDebugMessage("Running " + this.getDebugPrefixMessage(alertGR, rule) + " with actions: " + actions.remediations + ".");
},
debugMessageExecuteActionsInRemediations: function(alertGR, rule, actions, i) {
this.evtMgmtCommons.addDebugMessage("Running remediation for " + this.getDebugPrefixMessage(alertGR, rule) + " with remediation action: " + actions.remediations[i].action.getWorkflowId());
},
debugMessageExecuteActionsAfter: function(alertGR, rule) {
this.evtMgmtCommons.addDebugMessage("Finished " + this.getDebugPrefixMessage(alertGR, rule));
},
getDebugPrefixMessage: function(alertGR, rule) {
return "management rule " + rule.getName() + "(" + rule.getSysId() + ") for alert " + alertGR.number + "(" + alertGR.sys_id + ")";
},
loadAdditionalInfo: function(ruleList) {
this.startStep(this.type + ": loadAdditionalInfo");
//this object hods the additional info for the alert management rule,
//ruleDataMap is a map that holds the records of the sn_em_arm_additional_info
//in case the object is already is initialized in the correct domain, or there are no rules to run
//the function will return
var ruleDataMap = {};
var additionalInfoObj = {
ruleDataMap: ruleDataMap
};
if (ruleList.length == 0)
return additionalInfoObj;
// the rule list only contains active rules. But it is possible that an active rule has been defined as dependent on an inactive rule.
// In this case, the dependent rule should be be run immediately, even though the parent is inactive.
// But we only know which rules are inactive by whether they *fail* to appear in the ruleList.
// So here we convert ruleList into a map
var activeRules = {};
for (var i = 0; i < ruleList.length; i++) {
activeRules[ruleList[i].getSysId()] = ruleList[i];
}
var domain = this.evtMgmtCommons.getCurrentDomainID();
if (this.fRuleAdditionalInfo.hasOwnProperty(domain))
return this.fRuleAdditionalInfo[domain];
var dataGr = new GlideRecord(this.ADDITIONAL_INFO_TABLE);
dataGr.orderBy("sys_created_on"); //if we have duplications we want the oldest
dataGr.query();
var dependencyMap = {};
while (dataGr.next()) {
var ruleSysId = dataGr.getValue(this.ALERT_MGMT_RULE);
var obj = {
ruleSysId: ruleSysId,
useScript: dataGr.getValue(this.USE_SCRIPT),
dependentOnRule: dataGr.getValue(this.DEPENDENT_ON_RULE),
alertKeyField: dataGr.getValue(this.ALERT_KEY_FIELD),
alertKeyValue: dataGr.getValue(this.ALERT_KEY_VALUE),
alertKeyAppliesTo: dataGr.getValue(this.APPLIES_TO),
isAddInfoField: JSON.parse(dataGr.getValue(this.IS_ADD_INFO_FIELD)),
recordSysId: dataGr.getValue(this.SYS_ID)
};
if (ruleDataMap[ruleSysId]) { //Already have a record for this rule in the additional info table
gs.error("Alert Management Rule: " + ruleSysId + " Already exists in the additional info table, ignoring this record: " + dataGr.getValue(this.SYS_ID));
} else {
ruleDataMap[ruleSysId] = obj;
}
if (!gs.nil(obj.dependentOnRule)) {
// we have a dependency here, so store it in the dependencyt map
if (!dependencyMap[obj.dependentOnRule]) {
dependencyMap[obj.dependentOnRule] = [];
}
dependencyMap[obj.dependentOnRule].push(ruleSysId);
}
}
this.fRuleAdditionalInfo[domain] = additionalInfoObj;
additionalInfoObj.dependencyMap = dependencyMap;
additionalInfoObj.activeRuleMap = activeRules;
return this.fRuleAdditionalInfo[domain];
},
evaluateRuleScript: function(rule, ruleAddInfoMap, alertGR) {
this.startStep(this.type + ": evaluateRuleScript");
//can happen in flows where AdditionalInfo was not initiated , for example - reopen alert
if (!ruleAddInfoMap) {
ruleAddInfoMap = this.initiateAddInfoMap();
}
var ruleSysId = rule.getSysId();
var output = true;
if (ruleAddInfoMap.hasOwnProperty(ruleSysId)) {
if (ruleAddInfoMap[ruleSysId].useScript == 1) {
this.startStep(this.type + ": evaluateRuleScript - query AI table");
var sysId = ruleAddInfoMap[ruleSysId].recordSysId;
var scriptGr = new GlideRecord(this.ADDITIONAL_INFO_TABLE);
if (scriptGr.get(sysId)) {
this.startStep(this.type + ": evaluateRuleScript - evaluate script");
var evaluator = new GlideScopedEvaluator();
evaluator.putVariable('gr', alertGR);
output = evaluator.evaluateScript(scriptGr, this.SCRIPT_CONDITION);
}
}
}
if (gs.nil(output)) {
gs.error("rule " + rule.getName() + " script evaluation has failed ");
return false;
}
return output;
},
setStepManager: function(pSlowStepsManager) {
this.slowStepsManager = pSlowStepsManager;
},
startStep: function(pStep) {
if (typeof this.slowStepsManager !== "undefined") {
this.slowStepsManager.startStep(pStep);
}
},
onRuleComplete: function(alertGR, alertRuleId, passthroughParamsJson) {
this.startStep(this.type + ": onRuleComplete - start");
// the rule has finished running, now we can call its dependent rules
// get the rules from the cache
var relevantRules = this.evtMgmtAlertMgmtMediator.getReleveantAlertRules();
var ruleAdditionalInfo = this.loadAdditionalInfo(relevantRules);
var dependentRuleIds = ruleAdditionalInfo.dependencyMap[alertRuleId];
if (!dependentRuleIds) {
// this is a really far-fetched edge case, in case the dependency was removed while the rule was running, before the callback.
return;
}
var dependentRules = this.addActiveDependentRules([], ruleAdditionalInfo, dependentRuleIds);
// now we can loop back into iterateOverRules
this.startStep(this.type + ": onRuleComplete - callback to iterateOverRules");
// reload the execution map, just for this alert id
var passthroughParams = JSON.parse(passthroughParamsJson);
var map = this.evtMgmtAlertMgmtCommons.getAlertRuleExecutionMap([alertGR.sys_id]);
this.iterateOverRules(alertGR, dependentRules, false, passthroughParams.retrieveParams, map, null, true);
},
addActiveDependentRules: function(dependentRules, ruleAdditionalInfo, dependentRuleIds) {
this.startStep(this.type + ": addActiveDependentRules (recursive function)");
for (var i = 0; i < dependentRuleIds.length; i++) {
// if the rule is in the map, that's great. If it's not, that means it is inactive, and its dependencies should run immediately
var ruleId = dependentRuleIds[i];
var rule = ruleAdditionalInfo.activeRuleMap[ruleId];
if (rule) {
dependentRules.push(rule);
} else {
// I am inactive, so check if I have any dependencies, and if so, recurse
var myDependentRuleIds = ruleAdditionalInfo.dependencyMap[ruleId];
if (myDependentRuleIds) {
dependentRules = this.addActiveDependentRules(dependentRules, ruleAdditionalInfo, myDependentRuleIds);
}
}
}
return dependentRules;
},
getAddInfoFieldJsonForSRO: function(additionalInfo) {
if (!additionalInfo)
return undefined;
// whether this is an SRO alert or not, we may need the additional info
try {
var additionalInfoJSON = JSON.parse(additionalInfo);
if (!additionalInfoJSON)
return undefined;
return additionalInfoJSON;
} catch (e) {
gs.error("Alert Management - Fail to parse alert additional info: " + additionalInfo + "; Error Message: " + this.evtMgmtCommons.getExceptionMessage(e, true));
return undefined;
}
},
// Returns a trimed keys array (or if allrady fetched the same key)
getKeysListForSRO: function() {
if (!this.SROKeys) {
if (gs.nil(this.ALERT_KEY_IDENTIFIER_FIELD)) {
this.SROKeys = [];
} else {
var keys = this.ALERT_KEY_IDENTIFIER_FIELD.split(",");
for (var i = 0; i < keys.length; ++i) {
keys[i] = (keys[i]).trim();
}
this.SROKeys = keys;
}
}
return this.SROKeys;
},
isSroAlert: function(additionalInfoJSON) {
if (!additionalInfoJSON) // additionalInfoJSON undefined
return false;
var keys = this.getKeysListForSRO();
for (var i = 0; i < keys.length; ++i) {
if (!gs.nil(keys[i])) {
if (additionalInfoJSON.hasOwnProperty((keys[i]))) {
return true;
}
}
}
return false;
},
initiateAddInfoMap: function() {
this.startStep(this.type + ": initiateAddInfoMap");
var relevantRules = this.evtMgmtAlertMgmtMediator.getReleveantAlertRules();
var additionalInfo = this.loadAdditionalInfo(relevantRules);
var ruleAddInfoMap = additionalInfo.ruleDataMap;
return ruleAddInfoMap;
},
findApplicationService: function(alertGR) {
var data = [];
var query = this.QUERY_IMPACT_GRAPH;
if (query == 'false')
return data;
this.startStep(this.type + ": findApplicationService - get CI");
var alertCi = alertGR.getValue(this.CMDB_CI);
try {
if (alertCi) {
data = this.fApplicationServicesPerCI[alertCi];
if (data != undefined) {
return data;
}
// load the valid application services with this alert's CI in the impact graph, and cache them in fApplicationServicesPerCI
data = [];
this.startStep(this.type + ": findApplicationService - Query impact graph table");
var gr = new GlideRecord(this.IMPACT_GRAPH_TABLE);
gr.addQuery(this.CHILD, alertCi);
gr.addQuery(this.STATUS, "Valid");
gr.setLimit(this.MAX_APP_PER_CI);
gr.query();
this.startStep(this.type + ": findApplicationService - Loop through query results");
while (gr.next()) {
data.push(gr.getValue(this.BUSINESS_SERVICE));
}
if (data.length >= this.MAX_APP_PER_CI) {
gs.error('EvtMgmtAlertMgmtProcess: findApplicationService ' + 'exceeded ' + this.MAX_APP_PER_CI + ' Application Services for CI ' + alertGR.getValue("cmdb_ci"));
}
this.fApplicationServicesPerCI[alertCi] = data;
}
return data;
} finally {
this.startStep(this.type + ": findApplicationService - end");
}
},
matchAlertKeyValue: function(alertGR, thisRuleInfo, keyField, keyValue, keyAppliesTo, additionalInfoJSON) {
var keyFieldMatches = true; //for all rules without alert_key_field
var alertValue = "";
if (keyField) {
keyFieldMatches = false;
if (keyField != this.CMDB_CI) {
if (thisRuleInfo["isAddInfoField"] && additionalInfoJSON) {
alertValue = additionalInfoJSON[keyField]; //field in additional info
} else {
alertValue = alertGR.getValue(keyField); //alert field
}
if (keyValue == alertValue)
keyFieldMatches = true;
} else { //keyField == cmdb_ci
alertValue = alertGR.getValue(keyField);
if (keyAppliesTo != this.APPLIES_TO_CI) {
if (keyValue == alertValue)
keyFieldMatches = true; //the Alert's CI matches the rule's key value (AS)
}
if (keyAppliesTo != this.APPLIES_TO_SERVICE && (alertValue != keyValue)) {
var ApplicationServiceList = this.findApplicationService(alertGR);
for (var j = 0; j < ApplicationServiceList.length; j++) {
if (ApplicationServiceList[j] == keyValue) {
keyFieldMatches = true;
break;
}
}
}
}
}
return keyFieldMatches;
}
};
Sys ID
1bf511aab7d920107c038229ce11a920