Name
global.PatternPrePostHook
Description
This script provides the option to run scripts from sa_pattern_prepost_script as part of Discovery in 2 modes 1. Pre sensor payload processing 2. Post sensor payload processing 3. On pattern failure processing
Script
gs.include("PrototypeServer");
var PatternPrePostHook = Class.create();
var preSensorIntroductionComment = '/*\n * Pre sensor: You can change payload before it will be proccesed by Identification Engine.\n * Use IEJsonUtility in order to add relevant information to the payload\n * Input parameters in Pre sensor mode: payload, patternId\n */\n';
var postSensorIntroductionComment = '/*\n * Post sensor: You can update/add missing info to the DB based on result (Json) from\n * Identification Engine\n * Output parameters in Post sensor mode: payload\n */\n';
var prePostTemplateCommonPortion = '\n\nvar rtrn = {};\n\n// parsing the json string to a json object\nvar payloadObj = JSON.parse(payload);\n\n// Clearing payload string to save memory\npayload = null;\n\n';
var returnObjectCommonPortion = '// You can return a message and a status, on top of the input variables that you MUST return.\n// Returning the payload as a Json String is mandatory in case of a pre sensor script, and optional in\ case of post sensor script.\n// If you want to terminate the payload processing due to your business logic - you can set isSuccess to false.\nrtrn = {\n\t\'status\': {\n\t\t\'message\': \'Enter your message here\',\n\t\t\'isSuccess\' :true\n\t},\n\t\'patternId\': patternId';
var returnObjectPayloadPortion = ',\n\t\'payload\': JSON.stringify(payloadObj)';
var returnObjectClosingPortion = '\n};';
var businessLogicComment = '// Put your business logic here\n// For node logger, please use: prePostNodeLogger.info\\warn\\error\\debug(prePostLogPrefix + \'<YOUR_LOG_STATEMENT>\')\n\n';
PatternPrePostHook.preSensorTemplate = preSensorIntroductionComment + prePostTemplateCommonPortion + businessLogicComment + returnObjectCommonPortion + returnObjectPayloadPortion + returnObjectClosingPortion;
PatternPrePostHook.postSensorTemplate = postSensorIntroductionComment + prePostTemplateCommonPortion + businessLogicComment + returnObjectCommonPortion + returnObjectClosingPortion;
PatternPrePostHook.preExecTemplate = '/* \n * Pre execution: This script will run before the execution of the assigned pattern/s\n * It allows the user to add data that can be accessed by the running the pattern\n * This is done by adding variables to the scriptable PrePatternExecutionData object\n * Below is an example of the possible variables that can be added.\n */\n\nvar data = new SNC.PrePatternExecutionData();\n\n// Add a string with variable name \'stringA\'\ndata.addString(\'stringA\',\'string_value\');\n\n// Add a list with variable name \'listA\', value given must be a list\nvar lst = [\'list_first_value\',\'list_second_value\'];\ndata.addList(\'listA\',lst);\n\n// This will create a new table variable \'tableA\'\n// The value given must be a map, whose keys will be the tables fields and values the first row\ndata.addTableEntry(\'tableA\',{\n\t\'first_field\':\'row 1 arg1\',\n\t\'second_field\':\'row 1 arg2\'\n});\n\n// This will add a second row to the previous table \'tableA\'\n// Note that the keys in map must match the previous tables fields\ndata.addTableEntry(\'tableA\',{\n\t\'first_field\':\'row 2 arg3\',\n\t\'second_field\':\'row 2 arg4\'\n});\n\n// Use this method if you want the pattern not to be executed\n // data.executePattern(false);\n\n// Must return the data at end\nrtrn = data;';
PatternPrePostHook.onFailureTemplate = '/*\n * On Failure: You can do operations in case a pattern failed.\n */\nvar rtrn = {};\n\n' + businessLogicComment + returnObjectCommonPortion + returnObjectClosingPortion;
PatternPrePostHook.executionPhase = {
preSensor: 1,
postSensor: 2,
preExecution: 3,
onFailure: 4
};
PatternPrePostHook.LOGGER_NAME = 'PatternPrePostExecutor';
PatternPrePostHook.LOGGER_NAME_LOG_PREFIX = '[' + PatternPrePostHook.LOGGER_NAME + ']';
PatternPrePostHook.prototype = {
HD_DISCOVERY_TYPE: 1,
SM_DISCOVERY_TYPE: 2,
PATTERN_PREPOST_TABLE_NAME: "sa_pattern_prepost_script",
LOG_PREFIX: PatternPrePostHook.LOGGER_NAME_LOG_PREFIX + '[sys_script_include_a5aff88193321200248635bb357ffb4d]',
initialize: function(inputEccQueueSysId, outputEccQueueSysId) {
this.nodeLogger = new sn_automation.AutomationAPI().getNodeLogger(PatternPrePostHook.LOGGER_NAME);
// Pattern debugger simulator is initializing this "class" with no parameters, hence setting prefixes to default
this.preSensorLogPrefix = this.LOG_PREFIX;
this.postSensorLogPrefix = this.LOG_PREFIX;
this.onFailureLogPrefix = this.LOG_PREFIX;
if (inputEccQueueSysId)
this.preSensorLogPrefix += '[ecc_queue_' + inputEccQueueSysId + '] ';
if (outputEccQueueSysId) {
this.postSensorLogPrefix += '[ecc_queue_' + outputEccQueueSysId + '] ';
this.onFailureLogPrefix += '[ecc_queue_' + outputEccQueueSysId + '] ';
}
},
/**
* This function running script from table sa_pattern_prepost_script
* in order to perform pre sensor logic.
* For example: we can add additional info to the db after the payload was processed
* @method runPreProcess
* @param {Json} params with the following mandatory structure { 'patternId':'someid',payload: {some object} }
* @return {Json} params with the same structure as received
*/
runPreProcess: function(params) {
this.nodeLogger.info(this.preSensorLogPrefix + 'About to run pre-sensor scripts for pattern "' + params.patternId + '"');
this.nodeLogger.debug(this.preSensorLogPrefix + 'Post-sensors scripts parameters [resultHandler parameter is not a JS object, hence will always be empty]:\n' + JSON.stringify(params));
var patternSysId = this.getPatternSysIdByName(params.patternId);
var resultHandler = params.resultHandler;
var nodeName = params.nodeName;
if(gs.nil(patternSysId)) {
var errPatSysId = 'Abort runPreProcess operation due to null pattern sys_id';
this.nodeLogger.error(this.preSensorLogPrefix + errPatSysId);
resultHandler.addNodeToLogWithPages(errPatSysId, 'FAILURE', nodeName, '');
throw errPatSysId;
}
if (params.payload === null || gs.nil(params.payload) || params.payload == 'null') {
var errPayload = 'Abort runPreProcess operation due to empty payload. check the log for more information';
this.nodeLogger.error(this.preSensorLogPrefix + errPayload);
resultHandler.addNodeToLogWithPages(errPayload, 'FAILURE', nodeName, '');
throw errPayload;
}
var gr = this.getPrePostGlideRecords(patternSysId, PatternPrePostHook.executionPhase.preSensor);
// Define the success/failure function passed into processing.
var successFunc = function (params, gr, successMessage) {
var resultHandler = params.resultHandler;
var nodeName = params.nodeName;
var scriptName = gr.getValue('name');
resultHandler.addNodeToLogWithPages(successMessage, 'SUCCESS', nodeName, scriptName);
};
var failureFunc = function (params, gr, failureMessage) {
var resultHandler = params.resultHandler;
var nodeName = params.nodeName;
var scriptName = gr.getValue('name');
resultHandler.addNodeToLogWithPages(failureMessage, 'FAILURE', nodeName, scriptName);
throw 'name of failed script: ' + scriptName;
};
return this.runSelectedPreProcess(params, gr, successFunc, failureFunc);
},
/**
* This function runs the selected scripts from table sa_pattern_prepost_script
* in order to perform pre sensor logic.
* For example: we can add additional info to the db after the payload was processed
* @method runSelectedPreProcess
* @param {Json} params with the following mandatory structure { 'patternId':'someid',payload: {some object} }
* @gr GlideRecord which has queried for the desired pre-sensors.
* @successFunc function variable which is used to provide an option for logging successful processing.
* @failureFunc function variable which is used to provide an option for logging failed processing.
* @return {Json} params with the same structure as received
*/
runSelectedPreProcess: function(params, gr, successFunc, failureFunc) {
var updatedParams = params;
var totalExecutionTime = 0;
while(gr.next()) {
var result;
var scriptName = gr.getValue('name');
this.nodeLogger.info(this.preSensorLogPrefix + 'About to run pre-sensor: "' + scriptName + '"');
try{
var stop_watch_for_pre_sensor = new GlideStopWatch();
result = this.executeJsScript(gr, updatedParams, PatternPrePostHook.executionPhase.preSensor);
stop_watch_for_pre_sensor.stop();
totalExecutionTime = totalExecutionTime + stop_watch_for_pre_sensor.getTime();
this.nodeLogger.info(this.preSensorLogPrefix + 'Pre-sensor finished with execution time of '+stop_watch_for_pre_sensor.getTime()+' milliseconds.');
this.nodeLogger.debug(this.preSensorLogPrefix + 'Result returned:\n' + JSON.stringify(result));
} catch(err){
var failureMessage = 'Pre-sensor script "' + scriptName + '" failed due to: ' + err;
this.nodeLogger.error(this.preSensorLogPrefix + failureMessage);
failureFunc(params, gr, failureMessage);
}
if (!gs.nil(result.status) && result.status.isSuccess == true) {
updatedParams.payload = result.payload;
if(totalExecutionTime >= 0)
updatedParams.totalExecutionTime = totalExecutionTime;
else
updatedParams.totalExecutionTime = null;
var successMessage = 'Success: ' + result.status.message + ".";
this.nodeLogger.debug(this.preSensorLogPrefix + successMessage);
successFunc(params, gr, successMessage);
} else {
var failureMessage;
if(!gs.nil(result.status)){
failureMessage = 'Failure: ' + result.status.message + ".";
} else {
failureMessage = 'Failure: no result status.';
}
this.nodeLogger.error(this.preSensorLogPrefix + failureMessage);
failureFunc(params, gr, failureMessage);
}
}
return updatedParams;
},
needsPreProcessing: function(patternId) {
var logPrefix = this.preSensorLogPrefix || '';
var patternSysId = this.getPatternSysIdByName(patternId);
if(gs.nil(patternSysId)) {
var failureMessage = 'Abort runPreProcess operation due to null pattern sys_id';
this.nodeLogger.error(logPrefix + failureMessage);
throw failureMessage;
}
var gr = this.getPrePostGlideRecords(patternSysId, PatternPrePostHook.executionPhase.preSensor);
this.nodeLogger.debug(logPrefix + 'Found ' + gr.getRowCount() + ' pre-sensors for pattern');
return gr.hasNext();
},
needsPostProcessing: function(patternId) {
var logPrefix = this.postSensorLogPrefix || '';
var patternSysId = this.getPatternSysIdByName(patternId);
if(gs.nil(patternSysId)){
var failureMessage = 'Abort runPreProcess operation due to null pattern sys_id';
this.nodeLogger.error(logPrefix + failureMessage);
throw failureMessage;
}
var gr = this.getPrePostGlideRecords(patternSysId, PatternPrePostHook.executionPhase.postSensor);
this.nodeLogger.debug(logPrefix + 'Found ' + gr.getRowCount() + ' post-sensors for pattern');
return gr.hasNext();
},
/**
* This function running script from table sa_pattern_prepost_script
* in order to perform post sensor logic.
* For example: we can verify that some info was added to the DB.
* @method runPostProcess
* @param {Json} params with the following mandatory structure { 'patternId':'someid', payload: {some object} }
* @return {Json} params with the same structe as arrived
*/
runPostProcess: function(params) {
this.nodeLogger.info(this.postSensorLogPrefix + 'About to run post-sensor scripts for pattern "' + params.patternId + '"');
this.nodeLogger.debug(this.postSensorLogPrefix + 'Post-sensors scripts parameters [resultHandler parameter is not a JS object, hence will always be empty]:\n' + JSON.stringify(params));
var patternSysId = this.getPatternSysIdByName(params.patternId);
var resultHandler = params.resultHandler;
//variable for the pattern log
var nodeName = params.nodeName;
if (gs.nil(patternSysId)) {
var errPatSysId = 'Abort runPostProcess operation due to null pattern sys_id';
this.nodeLogger.error(this.postSensorLogPrefix + errPatSysId);
resultHandler.addNodeToLogWithPages(errPatSysId, 'FAILURE', nodeName, '');
throw errPatSysId;
}
var totalExecutionTime = 0;
var gr = this.getPrePostGlideRecords(patternSysId, PatternPrePostHook.executionPhase.postSensor);
while(gr.next()) {
var result;
var scriptName = gr.getValue('name');
this.nodeLogger.info(this.postSensorLogPrefix + 'About to run post-sensor: "' + scriptName + '"');
if (gr.getValue('use_split_payload') + '' != '1') {
this.nodeLogger.debug(this.postSensorLogPrefix + 'Using IRE output based post sensor. "use_split_payload" is set to "false" on the post-sensor');
params['payloadRecords'] = '';
}
else {
this.nodeLogger.debug(this.postSensorLogPrefix + 'Using GlideRecord based post sensor. "use_split_payload" is set to "true" on the post-sensor');
params['payloadRecords'] = params.resultHandler.getSaPagedPayloadQueryRecord(g_probe);
}
try{
var stop_watch_for_post_sensor = new GlideStopWatch();
result = this.executeJsScript(gr, params, PatternPrePostHook.executionPhase.postSensor);
stop_watch_for_post_sensor.stop();
totalExecutionTime = totalExecutionTime + stop_watch_for_post_sensor.getTime();
this.nodeLogger.info(this.postSensorLogPrefix + 'Post-sensor finished with execution time of '+stop_watch_for_post_sensor.getTime()+' milliseconds');
this.nodeLogger.debug(this.postSensorLogPrefix + 'Result returned:\n' + JSON.stringify(result));
} catch(err){
var failureMessage = 'Post-sensor script "' + scriptName + '" failed due to: ' + err;
this.nodeLogger.error(this.postSensorLogPrefix + failureMessage);
resultHandler.addNodeToLogWithNoPages(failureMessage, 'FAILURE', nodeName, scriptName);
throw 'name of failed script: ' + scriptName;
}
if (!gs.nil(result.status) && result.status.isSuccess == true) {
var successMessage = 'Success: ' + result.status.message + ".";
this.nodeLogger.debug(this.postSensorLogPrefix + successMessage);
gs.info('Result is success');
resultHandler.addNodeToLogWithNoPages(successMessage, 'SUCCESS', nodeName, scriptName);
} else {
var failureMessage;
if(!gs.nil(result.status)){
failureMessage = 'Failure: ' + result.status.message + ".";
} else {
failureMessage = 'Failure: no result status.';
}
this.nodeLogger.error(this.postSensorLogPrefix + failureMessage);
resultHandler.addNodeToLogWithNoPages(failureMessage, 'FAILURE', nodeName, scriptName);
throw 'Abort runPostProcess operation due to: ' + result.status.message + ' GlideRecord = ' + gr + ".";
}
}
if(totalExecutionTime >= 0)
params.totalExecutionTime = totalExecutionTime;
else
params.totalExecutionTime = null;
return params;
},
/**
* This function running script from table sa_pattern_prepost_script
* in order to perform on-failure logic.
* @method runOnFailure
* @param {Json} params with the following mandatory structure { 'patternId':'someid' }
* @return {Json} params with the same structe as arrived
*/
runOnFailure: function(params) {
this.nodeLogger.info(this.onFailureLogPrefix + 'About to run on-failure scripts for pattern "' + params.patternId + '"');
this.nodeLogger.debug(this.onFailureLogPrefix + 'On-failure scripts parameters [resultHandler parameter is not a JS object, hence will always be empty]:\n' + JSON.stringify(params));
var patternSysId = this.getPatternSysIdByName(params.patternId);
var resultHandler = params.resultHandler;
//variable for the pattern log
var nodeName = params.nodeName;
if (gs.nil(patternSysId)) {
var errPatSysId = 'Abort runOnFailure operation due to null pattern sys_id';
this.nodeLogger.error(this.onFailureLogPrefix + errPatSysId);
resultHandler.addNodeToLogWithPages(errPatSysId, 'FAILURE', nodeName, '');
throw errPatSysId;
}
var gr = this.getPrePostGlideRecords(patternSysId, PatternPrePostHook.executionPhase.onFailure);
while(gr.next()) {
var result;
var scriptName = gr.getValue('name');
try{
result = this.executeJsScript(gr, params, PatternPrePostHook.executionPhase.onFailure);
} catch(err){
var failureMessage = 'Running on failure script- ' + scriptName + ' failed due to: ' + err + ".";
resultHandler.addNodeToLogWithNoPages(failureMessage, 'FAILURE', nodeName, scriptName);
throw 'name of failed script: ' + scriptName;
}
if (!gs.nil(result.status) && result.status.isSuccess == true) {
var successMessage = 'Success: ' + result.status.message + ".";
this.nodeLogger.debug(this.onFailureLogPrefix + successMessage);
gs.debug('runOnFailure: result is success');
resultHandler.addNodeToLogWithNoPages(successMessage, 'SUCCESS', nodeName, scriptName);
} else {
var failureMessage;
if(!gs.nil(result.status)){
failureMessage = 'Failure: ' + result.status.message + ".";
} else {
failureMessage = 'Failure: no result status.';
}
resultHandler.addNodeToLogWithNoPages(failureMessage, 'FAILURE', nodeName, scriptName);
var detailedFailureMessage = 'Abort runOnFailure operation due to: ' + failureMessage + ' GlideRecord = ' + gr;
this.nodeLogger.error(this.onFailureLogPrefix + detailedFailureMessage);
throw detailedFailureMessage;
}
}
},
getPatternSysIdByName: function(patternName){
var gr = new GlideRecord('sa_pattern');
gr.addQuery("name", patternName);
gr.query();
if(gr.next())
return gr.sys_id;
return null;
},
getPrePostGlideRecords: function(patternId, whenToExec) {
var gr = new GlideRecord(this.PATTERN_PREPOST_TABLE_NAME);
gr.addQuery("active", true);
gr.addQuery("pattern", 'CONTAINS', patternId);
gr.addQuery("execution_type", this.HD_DISCOVERY_TYPE);
gr.addQuery("when_to_exec", whenToExec);
gr.orderBy("order");
gr.orderBy("name");
gr.query();
return gr;
},
/**
* This function executing script from GlideRecord
* @method executeJsScript
* @param {Json} params with the following structure { 'param1':'value1', ... }
* @return {Json} result {}
*/
executeJsScript: function(gr, params, execType) {
var logPrefix = this.getLogPrefixByExecutionPhase(execType);
params.prePostNodeLogger = this.nodeLogger;
params.prePostLogPrefix = logPrefix;
var evaluator = new GlideScopedEvaluator();
var result = evaluator.evaluateScript(gr, "script", params);
try {
this.nodeLogger.debug(logPrefix + 'The evaluation result is: ' + JSON.stringify(result));
} catch (e){
// nothing to do here...
}
if (this.isValidResultFormat(result, execType) == true){
return result;
} else {
var errorMessage = 'Abort executeJsScript due to invalid result format ';
this.nodeLogger.error(this.LOG_PREFIX + errorMessage);
throw errorMessage;
}
},
getLogPrefixByExecutionPhase: function(executionPhase) {
var logPrefix = this.LOG_PREFIX;
switch (executionPhase) {
case PatternPrePostHook.executionPhase.preSensor:
logPrefix = this.preSensorLogPrefix;
break;
case PatternPrePostHook.executionPhase.postSensor:
logPrefix = this.postSensorLogPrefix;
break;
case PatternPrePostHook.executionPhase.onFailure:
logPrefix = this.onFailureLogPrefix;
break;
}
return logPrefix;
},
/*
* This function is checking if the result format is valid
* Example of the result format:
* { "status":{"message":"test",
* "isSuccess":true},
* "patternId":"70a27f8593301200f81a35bb357ffb82",
* "payload":{JSON PAYLOAD FORMAT}
*/
isValidResultFormat: function(result, execType){
if(execType == PatternPrePostHook.executionPhase.preSensor && !result.hasOwnProperty('payload'))
return false;
if(result.hasOwnProperty('status') &&
result.status.hasOwnProperty('isSuccess') &&
result.status.hasOwnProperty('message')){
return true;
}
return false;
},
type: "PatternPrePostHook"
};
Sys ID
a5aff88193321200248635bb357ffb4d