Name
global.SLAConditionBase
Description
Base class of methods to test a contract_sla s conditions, at key points in the TaskSLA state machine (called from TaskSLAController) Extend this class to override specific methods and set the com.snc.sla.default_conditionclass property to use it as the default. this.sla contains the contract_sla GlideRecord and this.task contains the task GlideRecord. Use this._conditionMatches(conditionExpression) to evaluate the condition against the task record. var localSLACondition = Class.create(); localSLACondition.prototype = Object.extendsObject(SLAConditionBase, { ... } localSLACondition.attach() - if an instance of this SLA should be attached and started localSLACondition.pause() - if an instance of this SLA should be paused localSLACondition.complete() - if an instance of this SLA should be marked complete localSLACondition.reattach() - if an instance of this SLA should be reattached (marked completed, and then a new copy reapplied.) localSLACondition.cancel() - if an instance of this SLA should be cancelled
Script
var SLAConditionBase = Class.create();
SLAConditionBase.prototype = {
initialize : function(slaGR, taskGR, taskSLAgr) {
this.lu = new GSLog(this.SLA_CONDITION_LOG, this.type);
this.lu.includeTimestamp();
if (gs.getProperty(this.SLA_DATABASE_LOG, "db") == "node")
this.lu.disableDatabaseLogs();
this.setSLA(slaGR);
this.setTask(taskGR);
this.setTaskSLA(taskSLAgr);
this.caseSensitiveConditions = (gs.getProperty(this.SLA_CONDITION_CASE_SENSITIVE, 'false') == 'true');
this.slaContractUtil = new SLAContractUtil();
// if enable logging has been checked on the SLA definition up the log level to "debug"
if (this.sla && this.sla.enable_logging)
this.lu.setLevel(GSLog.DEBUG);
// debug, etc
this.timers = (gs.getProperty(this.SLA_CONDITION_TIMERS, 'false') == 'true');
if (this.timers)
this.sw = new GlideStopWatch();
},
SLA_CONDITION_LOG: 'com.snc.sla.condition.log',
SLA_CONDITION_CASE_SENSITIVE: 'com.snc.sla.condition.case_sensitive',
SLA_CONDITION_TIMERS: 'com.snc.sla.condition.timers',
SLA_DATABASE_LOG: 'com.snc.sla.log.destination',
SLA_SERVICE_OFFERING: 'com.snc.service.offering.field',
ON_CONDITION: "on_condition",
NO_MATCH: "no_match",
NEVER: "never",
setSLA: function(slaGR, taskGR) {
if (slaGR && slaGR instanceof GlideElementReference) {
this.sla = new GlideRecord("contract_sla");
this.sla.addDomainQuery(taskGR);
this.sla.get("" + slaGR);
} else
this.sla = slaGR;
},
setTask: function(taskGR) {
this.task = taskGR;
},
setTaskSLA: function(taskSLAgr) {
this.taskSLA = taskSLAgr;
},
// True if an instance of this SLA should be attached and started
attach: function() {
if (!this._conditionMatches(this.sla.start_condition))
return false;
return (!this.complete() && !this.cancel()); // don't start, if completion (stop) condition is also true
},
// True if an instance of this SLA should be paused.
pause: function() {
return (this._conditionMatches(this.sla.pause_condition));
},
resume: function() {
// Only use the condition to resume if when to resume is on_consition. All other cases, default to original behaviour
if (this.sla.when_to_resume + "" == this.ON_CONDITION)
return this._conditionMatches(this.sla.resume_condition);
return !this._conditionMatches(this.sla.pause_condition);
},
// True if an instance of this SLA should be completed.
complete: function() {
// XXX: what happens if there isn't a stop_condition? Should we default to stopping when the task goes inactive?
return (this._conditionMatches(this.sla.stop_condition));
},
// True if an instance of this SLA should be completed and a new one started
reattach : function(newSLADefIds) {
return (this._conditionMatches(this.sla.reset_condition) &&
this.attach() && !this._slaAlreadyCreated(newSLADefIds, this.sla.sys_id + ''));
},
// True if an instance of this SLA should be cancelled
// (tested after, and only if (complete() || reattach()) is false)
cancel: function() {
if (this.sla.when_to_cancel + "" == this.NEVER)
return false;
// If when_to_cancel is on_condition, use the cancel condition. All other cases default to original behaviour
var cancelMatch = false;
if (this.sla.when_to_cancel + "" == this.ON_CONDITION)
cancelMatch = this._conditionMatches(this.sla.cancel_condition);
else
cancelMatch = !(this._conditionMatches(this.sla.start_condition) && !this._conditionMatches(this.sla.stop_condition));
if (!this.slaContractUtil.ignoreContract(this.task.getRecordClassName()))
cancelMatch = cancelMatch || this._cancelContractSLA();
// cancel if the attach (start) condition is no longer true
// or if the CI has changed
return (cancelMatch || this._cancelServiceOffering());
},
hasAdvancedConditions: function() {
if (!this.sla)
return false;
var resetCondition = this.sla.getValue("reset_condition");
if (!resetCondition)
return false;
return this._isConditionAdvanced(resetCondition);
},
// true if the contract attached to task is changed, as the SLA's attached to the contract will be different
_cancelContractSLA: function() {
// Check whether processing non-contractual SLAs when task SLA does not have attached contract
var contractGR = this.task.contract;
if (!this.slaContractUtil.slaHasContract(this.sla.sys_id)){
if ((this.task.getValue('contract') == null && !this.slaContractUtil.hasContractProperty()) // not cancel if task doesn't have contract either (for non-legacy instances having the contract table property)
|| this.slaContractUtil.processNonContractualSLAs(contractGR)) // or if task attached to contract allows non-contractual SLAs
return false;
}
// if task SLA has contract, check it is still the same contract as the task
if (this.slaContractUtil.isContractAttachedToSLA(contractGR.sys_id, this.sla.sys_id))
return false;
if (this.lu.atLevel(GSLog.INFO))
this.lu.logInfo("canceling Contract SLA: " + this.sla.name + " - task is now against different contract");
return true;
},
///////////
// True if the task is switched to a different CI from the existing active service-offering SLA
_cancelServiceOffering: function() {
if (!new SLAUtil().isServiceCommitmentSLA(this.sla))
return false;
var serviceOfferingField = gs.getProperty(this.SLA_SERVICE_OFFERING, 'cmdb_ci');
var soc = new GlideRecord("service_offering_commitment");
soc.addQuery("service_commitment.type", "SLA");
soc.addQuery("service_commitment.sla", this.sla.sys_id + '');
soc.addQuery("service_offering", this.task.getValue(serviceOfferingField));
soc.query();
if (soc.hasNext())
return false;
if (this.lu.atLevel(GSLog.INFO))
this.lu.logInfo("canceling Service Offering SLA: " + this.sla.name + " - task is now against different CI");
return true;
},
// true only if condition exists and matches, for this.task
_conditionMatches: function(condition) {
if (!condition)
return false;
var sw;
if (this.timers)
sw = new GlideStopWatch();
var value;
try {
value = SNC.Filter.checkRecord(this.task, "" + condition, true, this.caseSensitiveConditions);
}
catch (e) {
if (this.lu.atLevel(GSLog.NOTICE))
this.lu.logNotice('_conditionMatches: [' + condition + '] caught exception ' + e);
}
if (this.lu.atLevel(GSLog.DEBUG))
this.lu.logDebug('_conditionMatches: [' + condition + '] on ' + this.task.number + ' [' + this.task.sys_id +'] => ' + value);
if (this.timers) {
sw.log('_conditionMatches complete');
this.sw.log('SLAConditionBase complete');
}
return value;
},
// true if in the same process already created an SLA instance which would
// now be completed, followed by another SLA instance being created
_slaAlreadyCreated : function(newSLADefIds, slaDefId) {
var slaAlreadyCreated = false;
if (JSUtil.notNil(newSLADefIds) && JSUtil.notNil(slaDefId)) {
slaAlreadyCreated = (newSLADefIds.join().indexOf(slaDefId) > -1);
}
return slaAlreadyCreated;
},
_isConditionAdvanced: function(condition) {
if (!condition)
return false;
var advancedOperators = Object.keys(SLAConditionBase.ADVANCED_CONDITION_OPERATORS);
if (!advancedOperators || advancedOperators.length === 0)
return false;
if (!advancedOperators.some(function(operator) {return condition.indexOf(operator) >= 0;}))
return false;
var queryString = new GlideQueryString(this.sla.getValue("collection"), condition);
queryString.deserialize();
var queryTerms = queryString.getTerms();
for (var i = 0; i < queryTerms.size(); i++) {
var queryTermOperator = "" + queryTerms.get(i).getOperator();
if (SLAConditionBase.ADVANCED_CONDITION_OPERATORS.hasOwnProperty(queryTermOperator))
return true;
}
return false;
},
type: 'SLAConditionBase'
};
SLAConditionBase.ADVANCED_CONDITION_OPERATORS = {
"VALCHANGES": true,
"CHANGESFROM": true,
"CHANGESTO": true
};
Sys ID
6cbf4dca7f000001763341f65c6ff1cd