Name

sn_cimaf.CIActionEngineSNC

Description

No description available

Script

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

  CI_AVAILABILITY_EXT_POINT: "sn_cimaf.CIAvailabilityHandler",

  TABLES: {
  	CI_ACTION: "sn_cimaf_action",
  	CMDB_CI: "cmdb_ci",
  	ACTION_CONFIG: "sn_cimaf_action_config",
  	ACTION_PARAMETER: "sn_cimaf_action_parameter",
  	ACTION_REQUEST: "sn_cimaf_action_request",
  	ACTION_OUTPUT: "sn_cimaf_action_output",
  	ACTION_ROLE: "sn_cimaf_action_role",
  	USER_CRITERIA_ACTION_INCLUSION: "sn_cimaf_action_user_criteria_mtom",
  	USER_CRITERIA_ACTION_EXCLUSION: "sn_cimaf_action_user_criteria_no_mtom"
  },

  FIELDS: {
  	SYS_ID: "sys_id",
  	SYS_DOMAIN: "sys_domain",
  	ACTION_CONFIG: {
  		action: "action",
  		execution_flow: "execution_flow",
  		execution_script: "execution_script",
  		order: "order"
  	},
  	ACTION_PARAMETER: {
  		model: "model",
  		element: "element",
  		mandatory: "mandatory",
  		default_value: "default_value"
  	},
  	ACTION_REQUEST: {
  		state: "state",
  		action_config: "action_config",
  		configuration_item: "configuration_item",
  		action_parameters: "action_parameters",
  		sys_created_on: "sys_created_on"
  	},
  	ACTION_OUTPUT: {
  		action_command: "action_command",
  		action_request: "action_request",
  		payload: "payload",
  		state: "state",
  		request_id: "request_id"
  	},
  	ACTION_ROLE: {
  		ACTION: "action",
  		ROLE: "role"
  	},
  	USER_CRITERIA_ACTION_INCLUSION: {
  		ACTION: "action",
  		USER_CRITERIA: "user_criteria"
  	},
  	USER_CRITERIA_ACTION_EXCLUSION: {
  		ACTION: "action",
  		USER_CRITERIA: "user_criteria"
  	}
  },

  STATE: {
  	ACTION_REQUEST: {
  		in_progress: "in_progress",
  		completed: "completed",
  		failed: "failed"
  	}
  },

  EXECUTE_ACTION_TYPE: {
  	FLOW: "flow",
  	SCRIPT: "script"
  },

  USER_CRITERIA: "user_criteria",
  
  PROPERTIES: {
  	ACTION_REQUEST_DUPLICATE_REQUEST_TIME: {
  		name: "sn_cimaf.action_request.duplicate_request_time_limit",
  		defaultValue: 5
  	}
  },
  
  initialize: function() {
  	this.ciActionHelper = new CIActionHelper();
  },

  execute: function(ciAction, ci, actionParams) {
  	if (!ci) {
  		gs.error("[CIActionEngine]: provide either the GlideRecord reference or sys_id of the CI item");
  		return;
  	}

  	if (!ciAction) {
  		gs.error("[CIActionEngine]: provide either the GlideRecord reference or sys_id of the Action Definition record");
  		return;
  	}

  	if (typeof ciAction === 'string') {
  		if (this.ciActionHelper.isSysId(ciAction)) {
  			ciAction = this.ciActionHelper._getGlideRecord(this.TABLES.CI_ACTION, ciAction);
  		} else {
  			ciAction = this.ciActionHelper._getGlideRecordByInternalName(this.TABLES.CI_ACTION, ciAction);
  		}
  	}

  	if (typeof ci === 'string') {
  		ci = this._getGlideRecord(ciAction.ci_class, ci);
  	}

  	if (typeof actionParams === 'string') {
  		try {
  			actionParams = JSON.parse(actionParams);
  		} catch (e) {
  			gs.error("[CIActionEngine - execute]: Invalid actionParams");
  			return;
  		}
  	} else {
  		actionParams = actionParams || {};
  	}
  	
  	if (!ci || !ci.isValidRecord()) {
  		gs.error("[CIActionEngine]: Provided CI is not a valid record");
  		return;
  	}

  	if (!ciAction || !ciAction.isValidRecord()) {
  		gs.error("[CIActionEngine]: Provided Action is not a valid record");
  		return;
  	}
  	
  	if (!this.isAuthorized(ciAction)) {
  		gs.error("[CIActionEngine]: User is not authorized to perform provided Action");
  		return;
  	}

  	var actionRequestId = this._checkDuplicateRequestInProgress(ciAction.getUniqueValue(), ci.getUniqueValue(), actionParams);
  	if (actionRequestId) {
  		return actionRequestId;
  	}

  	var actionConfig = this._getActionConfig(ciAction, ci);
  	if (!actionConfig) {
  		gs.error("[CIActionEngine]: Did not find any matching Action config record for the CI item " + ci.getDisplayValue());
  		return;
  	}
  	
  	if (!this._isActionParamsValid(actionConfig, actionParams)) {
  		gs.error("[CIActionEngine]: Action parameters missing or not valid for action config " + actionConfig.getDisplayValue());
  		return;
  	}

  	var ciDomain = ci.getValue(this.FIELDS.SYS_DOMAIN);

  	try {
  		var createActionRequestInputs = {};
  		createActionRequestInputs['action_config_sys_id'] = actionConfig.getUniqueValue();
  		createActionRequestInputs['ci_sys_id'] = ci.getUniqueValue();
  		createActionRequestInputs['action_params'] = actionParams;

  		var result = sn_fd.FlowAPI.getRunner()
  						.action('sn_cimaf.create_action_request_record')
  						.inForeground()
  						.inDomain(ciDomain)
  						.withInputs(createActionRequestInputs)
  						.run();

  		var outputs = result.getOutputs();
  		actionRequestId = outputs['action_request_sys_id'];
  	} catch (ex) {
  		gs.error("[CIActionEngine]: Error while creating action request record with inputs " + JSON.stringify(createActionRequestInputs) + ". Error: " + ex);
  		return;
  	}

  	if (!actionRequestId) {
  		gs.error("[CIActionEngine]: Could not create action request record for action config " + actionConfig.getDisplayValue() + " and CI item " + ci.getDisplayValue());
  		return;
  	}
  	var ciActionExecutionInputs = {};
  	ciActionExecutionInputs['skip_pre_request_checks'] = false;
  	ciActionExecutionInputs['action_request_sys_id'] = actionRequestId;
  	ciActionExecutionInputs['action_config_sys_id'] = actionConfig.getUniqueValue();
  	ciActionExecutionInputs['action_params'] = actionParams;
  	ciActionExecutionInputs['ci_sys_id'] = ci.getUniqueValue();
  	try {
  		sn_fd.FlowAPI.getRunner()
  			.subflow('sn_cimaf.ci_action_execution')
  			.inBackground()
  			.inDomain(ciDomain)
  			.withInputs(ciActionExecutionInputs)
  			.run();
  	} catch (ex) {
  		var actionHelper = new CIActionHelper();
  		actionHelper.updateActionRequestById(actionRequestId, this.STATE.ACTION_REQUEST.failed);
  		gs.error("[CIActionEngine]: Error while initiating ci action execution subflow with inputs " + JSON.stringify(ciActionExecutionInputs) + ". Error: " + ex.getMessage());
  		return;
  	}
  	return actionRequestId;
  },
  
  /**
  * @param Object ciAction - GlideRecord reference to the the Action record
  * @return Boolean value indicating if current logged-in user is authorized to perform given action
  **/
  isAuthorized: function(ciAction) {
  	var isUserRoleAllowed = this._isUserRoleAllowed(ciAction);
  	var isUserCriteriaIncluded = this._isUserCriteriaIncluded(ciAction);
  	var isUserCriteriaExcluded = this._isUserCriteriaExcluded(ciAction);
  	if (!isUserRoleAllowed['isConfigured'] && !isUserCriteriaIncluded['isConfigured'] && !isUserCriteriaExcluded['isConfigured'])
  		return false;
  	if (!isUserRoleAllowed['status'] || !isUserCriteriaIncluded['status'] || isUserCriteriaExcluded['status'])
  		return false;
  	return true;
  },

  getActionRequestOutputById: function(actionRequestSysId) {
  	if (!actionRequestSysId) {
  		gs.error("[CIActionEngine - getActionRequestOutputById]: Invalid action request sys id");
  		return;
  	}
  	var actionRequestGr = this._getGlideRecord(this.TABLES.ACTION_REQUEST, actionRequestSysId);
  	if (actionRequestGr) {
  		return this.getActionRequestOutput(actionRequestGr);
  	}
  },

  getActionRequestOutput: function(actionRequestGr) {
  	if (!this._isValidGr(actionRequestGr)) {
  		gs.error("[CIActionEngine - getActionRequestOutput]: Invalid action request record");
  		return;
  	}
  	var actionOutputFields = this.FIELDS.ACTION_OUTPUT;
  	var requiredActionOutputFields = [this.FIELDS.SYS_ID, actionOutputFields.action_command, actionOutputFields.payload,
  		actionOutputFields.state, actionOutputFields.request_id];
  	var actionOutputGr = new GlideRecord(this.TABLES.ACTION_OUTPUT);
  	actionOutputGr.addQuery(actionOutputFields.action_request, actionRequestGr.getUniqueValue());
  	actionOutputGr.query();
  	var actionOutputs = [];
  	while (actionOutputGr.next()) {
  		var actionOutput = {};
  		for (var i = 0; i < requiredActionOutputFields.length; i++) {
  			var field = requiredActionOutputFields[i];
  			actionOutput[field] = actionOutputGr.getValue(field);
  		}
  		actionOutputs.push(actionOutput);
  	}
  	var actionRequestOutput = {};
  	actionRequestOutput[this.FIELDS.SYS_ID] = actionRequestGr.getUniqueValue();
  	actionRequestOutput[this.FIELDS.ACTION_REQUEST.state] = actionRequestGr.getValue(this.FIELDS.ACTION_REQUEST.state);
  	actionRequestOutput[this.TABLES.ACTION_OUTPUT] = actionOutputs;
  	return actionRequestOutput;
  },

  getExecutingActionsByCI: function(ciGrOrSysId) {
  	var ciSysId = this._isValidGr(ciGrOrSysId) ? ciGrOrSysId.getUniqueValue() : ciGrOrSysId;
  	if (!ciSysId) {
  		gs.error("[CIActionEngine - getRunningActionsByCI]: Invalid CI");
  		return;
  	}
  	var result = [];
  	var actionRequestGr = new GlideRecord(this.TABLES.ACTION_REQUEST);
  	actionRequestGr.addQuery(this.FIELDS.ACTION_REQUEST.configuration_item, ciSysId);
  	actionRequestGr.addQuery(this.FIELDS.ACTION_REQUEST.state, this.STATE.ACTION_REQUEST.in_progress);
  	actionRequestGr.query();
  	while (actionRequestGr.next()) {
  		result.push(this.getActionRequestOutput(actionRequestGr));
  	}
  	return result;
  },

  _isUserRoleAllowed: function(ciAction) {
  	var actionRoleGr = new GlideRecord(this.TABLES.ACTION_ROLE);
  	actionRoleGr.addQuery(this.FIELDS.ACTION_ROLE.ACTION, ciAction.getUniqueValue());
  	actionRoleGr.addNotNullQuery(this.FIELDS.ACTION_ROLE.ROLE);
  	actionRoleGr.query();
  	if (!actionRoleGr.hasNext()){
  		return {
  			"isConfigured": false,
  			"status": true
  		};
  	}
  	while (actionRoleGr.next()){
  		if (gs.hasRole(actionRoleGr.role.name)){
  			return {
  				"isConfigured": true,
  				"status": true
  			};
  		}
  	}
  	return {
  		"isConfigured": true,
  		"status": false
  	};
  },

  _isUserCriteriaIncluded: function(ciAction) {
  	var includedUCs = this._fetchAssociatedUCs(this.TABLES.USER_CRITERIA_ACTION_INCLUSION,
  										this.FIELDS.USER_CRITERIA_ACTION_INCLUSION.ACTION,
  										ciAction.getUniqueValue());
  	if (!includedUCs.length){
  		return {
  			"isConfigured": false,
  			"status": true
  		};
  	}
  	return {
  		"isConfigured": true,
  		"status": sn_uc.UserCriteriaLoader.userMatches(gs.getUserID(), includedUCs)
  	};
  },

  _isUserCriteriaExcluded: function(ciAction) {
  	var excludedUCs = this._fetchAssociatedUCs(this.TABLES.USER_CRITERIA_ACTION_EXCLUSION,
  										this.FIELDS.USER_CRITERIA_ACTION_EXCLUSION.ACTION,
  										ciAction.getUniqueValue());
  	if (!excludedUCs.length){
  		return {
  			"isConfigured": false,
  			"status": false
  		};
  	}
  	return {
  		"isConfigured": true,
  		"status": sn_uc.UserCriteriaLoader.userMatches(gs.getUserID(), excludedUCs)
  	};
  },

  _fetchAssociatedUCs: function(tableName, columnName, columnValue) {
  	var gr = new GlideRecord(tableName);
  	gr.addQuery(columnName, columnValue);
  	gr.addNotNullQuery(this.USER_CRITERIA);
  	gr.query();
  	var ucs = [];
  	while (gr.next())
  		ucs.push(gr.getValue(this.USER_CRITERIA));
  	return ucs;
  },

  _getActionConfig: function(ciActionGr, cmdbCiGr) {
  	var actionConfigGr = new GlideRecord(this.TABLES.ACTION_CONFIG);
  	actionConfigGr.addQuery(this.FIELDS.ACTION_CONFIG.action, ciActionGr.getUniqueValue());
  	actionConfigGr.orderBy(this.FIELDS.ACTION_CONFIG.order);
  	actionConfigGr.query();

  	while (actionConfigGr.next()) {
  		if (
  			(
  				(actionConfigGr.action_type == this.EXECUTE_ACTION_TYPE.FLOW && global.JSUtil.notNil(actionConfigGr.execution_flow)) ||
  				(actionConfigGr.action_type == this.EXECUTE_ACTION_TYPE.SCRIPT && global.JSUtil.notNil(actionConfigGr.execution_script)) ||
  				(global.JSUtil.notNil(actionConfigGr.provider) && global.JSUtil.notNil(actionConfigGr.provider.default_action_execution_flow))
  			) &&
  			this._isActionConfigApplicable(actionConfigGr, cmdbCiGr))
  			return actionConfigGr;
  	}

  	return null;
  },

  _isProviderApplicable: function(provider, cmdbCiGr) {
  	var extPoints = new GlideScriptedExtensionPoint().getExtensions(this.CI_AVAILABILITY_EXT_POINT);
  	if (!extPoints.length) {
  		gs.info("[_isProviderApplicable]: Did not find any extension point defined");
  		return false;
  	}
  	for (var i = 0; i < extPoints.length; i++) {
  		var extPointSI = extPoints[i];
  		if (typeof extPointSI.getProvider == "function" && extPointSI.getProvider() === provider && extPointSI.isProviderApplicable(cmdbCiGr)) {
  			return true;
  		}
  	}
  	return false;
  },

  _isActionConfigApplicable: function(actionConfigGr, cmdbCiGr) {
  	if (!this._isProviderApplicable(actionConfigGr.getValue("provider"), cmdbCiGr)) {
  		return false;
  	}
  	var isCiConditionMatching;
  	if (actionConfigGr.match_ci_extensions + "" === 'true') {
  		var tableExtension = new GlideTableHierarchy(actionConfigGr.ci_class + "").getTableExtensions();
  		tableExtension.push(actionConfigGr.ci_class + "");
  		isCiConditionMatching = tableExtension.indexOf(cmdbCiGr.sys_class_name + "") > -1;
  	} else {
  		isCiConditionMatching = (actionConfigGr.ci_class + "" === cmdbCiGr.sys_class_name + "");
  	}

  	isCiConditionMatching = isCiConditionMatching && GlideFilter.checkRecord(cmdbCiGr, actionConfigGr.ci_conditions + "");
  	return isCiConditionMatching;
  },

  _isActionParamsValid: function(actionConfig, actionParams) {
  	var actionParamsGr = new GlideRecord(this.TABLES.ACTION_PARAMETER);
  	actionParamsGr.addActiveQuery();
  	actionParamsGr.addQuery(this.FIELDS.ACTION_PARAMETER.model, actionConfig.getUniqueValue());
  	actionParamsGr.query();
  	var activeParams = [];
  	while (actionParamsGr.next()) {
  		var paramName = actionParamsGr.getValue(this.FIELDS.ACTION_PARAMETER.element);
  		if(typeof actionParams[paramName] === 'undefined')
  			actionParams[paramName] = actionParamsGr.getValue(this.FIELDS.ACTION_PARAMETER.default_value) || "";
  		var isParamMandatory = actionParamsGr.getValue(this.FIELDS.ACTION_PARAMETER.mandatory) == "1";
  		if(isParamMandatory && actionParams[paramName] === "")
  			return false;
  		activeParams.push(paramName);
  	}

  	var actionParamsKeys = Object.keys(actionParams);
  	for(var i = 0; i < actionParamsKeys.length; i++) {
  		var param = actionParamsKeys[i];
  		if(activeParams.indexOf(param) == -1) {
  			gs.info("[CIActionEngine]: Action parameter - " + param + " is inactive or not configured for the Action configuration");
  			delete actionParams[param];
  		}
  	}

  	return true;
  },

  _getGlideRecord: function(tableName, sysId) {
  	var gr = new GlideRecord(tableName);
  	if (gr.get(sysId))
  		return gr;
  },

  _checkDuplicateRequestInProgress:function(ciActionSysId, ciSysId, ciActionParams) {
  	var actionRequestGr = new GlideRecord(this.TABLES.ACTION_REQUEST);
  	actionRequestGr.addQuery(this.FIELDS.ACTION_REQUEST.state, this.STATE.ACTION_REQUEST.in_progress);
  	actionRequestGr.addQuery(this.FIELDS.ACTION_REQUEST.configuration_item, ciSysId);
  	actionRequestGr.addQuery(this.FIELDS.ACTION_REQUEST.action_config + '.' + this.FIELDS.ACTION_CONFIG.action, ciActionSysId);
  	var timeLimit = gs.getProperty(this.PROPERTIES.ACTION_REQUEST_DUPLICATE_REQUEST_TIME.name, this.PROPERTIES.ACTION_REQUEST_DUPLICATE_REQUEST_TIME.defaultValue);
  	actionRequestGr.addQuery(this.FIELDS.ACTION_REQUEST.sys_created_on + "RELATIVEGT@minute@ago@" + timeLimit);
  	actionRequestGr.query();

  	while (actionRequestGr.next()) {
  		var result = this.compareJSON(this.getActionParams(actionRequestGr), ciActionParams);
  		if (result) {
  			return actionRequestGr.getUniqueValue();
  		}
  	}
  },
  
  getActionParams: function(actionRequestGr) {
  	var actionParamGr = new GlideRecord(this.TABLES.ACTION_PARAMETER);
  	actionParamGr.addActiveQuery();
  	actionParamGr.addQuery(this.FIELDS.ACTION_PARAMETER.model, actionRequestGr.getValue(this.FIELDS.ACTION_REQUEST.action_config));
  	actionParamGr.query();
  	var actionParams = {};
  	var execParams = actionRequestGr[this.FIELDS.ACTION_REQUEST.action_parameters];
  	while (actionParamGr.next()) {
  		var paramName = actionParamGr.getValue(this.FIELDS.ACTION_PARAMETER.element);
  		if (execParams[paramName])
  			actionParams[paramName] = execParams[paramName] + "";
  	}
  	return actionParams;
  },
  
  compareJSON: function(param1, param2) {
  	var keys = Object.keys(param1);
  	for(var i = 0; i < keys.length; i++) {
  		if (!param2.hasOwnProperty(keys[i]) || param1[keys[i]] !== param2[keys[i]]) {
  			return false;
  		}
  	}
  	return true;
  },

  _isValidGr: function(gr) {
  	return gr && gr instanceof GlideRecord && gr.isValidRecord();
  },

  type: 'CIActionEngineSNC'
};

Sys ID

f368bdee77211110a3f706e57b5a997d

Offical Documentation

Official Docs: