Name
global.ChangeConflictHandlerSNC
Description
Tracks conflicts derived by the ChangeCheckConflicts script-include and is used to save them to the database.
Script
var ChangeConflictHandlerSNC = Class.create();
ChangeConflictHandlerSNC.CONFLICT = "conflict";
ChangeConflictHandlerSNC.HAS_BEEN_HANDLED = "hasBeenHandled";
ChangeConflictHandlerSNC.CHANGE_CONFLICT_HANDLER_LOG = "change.conflict.handler.log";
ChangeConflictHandlerSNC.prototype = {
initialize: function (dumpCount, consolidatedConflicts, sourceRecordCISysId) {
this.changeConflictContainer = {};
this.addedcount = 0; // current count of conflicts held in this class
this.savedCount = 0; // total change conflict records by this class
this.dumpCount = dumpCount; // how many conflict records to collect before writing them out to database
this.consolidatedConflicts = typeof consolidatedConflicts !== "undefined" ? consolidatedConflicts : false; //Reduce the number of conflicts that are generated
this.sourceRecordCISysId = sourceRecordCISysId || ""; // Configuration item set in the cmdb_ci field of the source record, used when consolidating conflicts
this.lu = new GSLog(ChangeConflictHandler.CHANGE_CONFLICT_HANDLER_LOG, this.type);
this.lu.includeTimestamp();
},
addChangeConflict: function(changeConflict) {
var strChangeConflict = changeConflict.toString();
if (this.changeConflictContainer[strChangeConflict] != ChangeConflictHandler.HAS_BEEN_HANDLED) {
this.changeConflictContainer[strChangeConflict] = changeConflict;
++this.addedcount;
}
// Do not use batch insert if we are consolidating conflicts and only if we have reached the dumpCount.
if (!this.consolidatedConflicts && this.addedcount == this.dumpCount)
this.saveConflicts();
},
getConflicts: function() {
return this.changeConflictContainer;
},
/**
* Insert all of the derived conflicts
*/
saveConflicts: function () {
if (this.consolidatedConflicts) {
this._saveConsolidatedConflicts();
return this.savedCount;
}
var conflictsMapper = new GlideRecord(ChangeConflictHandler.CONFLICT);
var key = null;
for (key in this.changeConflictContainer) {
var currentChangeConflict = this.changeConflictContainer[key];
if (currentChangeConflict != ChangeConflictHandler.HAS_BEEN_HANDLED) {
conflictsMapper.initialize();
conflictsMapper.configuration_item = currentChangeConflict.configurationItemId;
conflictsMapper.change = currentChangeConflict.changeId;
conflictsMapper.type = currentChangeConflict.ctype;
conflictsMapper.conflicting_change = currentChangeConflict.conflictingChangeId;
conflictsMapper.related_configuration_item = currentChangeConflict.relatedCi;
conflictsMapper.schedule = currentChangeConflict.scheduleId;
conflictsMapper.impacted_service = currentChangeConflict.impactedService;
conflictsMapper.insert();
this.savedCount++;
}
}
for (key in this.changeConflictContainer)
this.changeConflictContainer[key] = ChangeConflictHandler.HAS_BEEN_HANDLED;
this.addedcount = 0;
return this.savedCount;
},
deleteConflictsByChangeId: function(changeId, checkAccess) {
var conflictsMapper = null;
if (checkAccess)
conflictsMapper = new GlideRecordSecure(ChangeConflictHandler.CONFLICT);
else
conflictsMapper = new GlideRecord(ChangeConflictHandler.CONFLICT);
conflictsMapper.addQuery('change', changeId);
conflictsMapper.deleteMultiple();
},
_saveConsolidatedConflicts: function () {
var conflictTypes = new ChangeCheckConflicts().buildConflictTypes();
// Object will be used to track each occurence of a conflict type mapped to a source; each unique schedule or conflicting change.
var conflicts = this._prepareConsolidatedConflictTracker(conflictTypes);
if (this.lu.atLevel(GSLog.DEBUG))
this.lu.logDebug("conflicts prepared: " + JSON.stringify(conflicts, 3,3,3));
// Populate the 'conflicts' object with the rows we need to insert
Object.keys(this.changeConflictContainer).forEach(function(conflictKey) {
var currentChangeConflict = this.changeConflictContainer[conflictKey];
if (currentChangeConflict != ChangeConflictHandler.HAS_BEEN_HANDLED) {
var itemSysId = currentChangeConflict[conflicts[currentChangeConflict.ctype].source];
if (this.lu.atLevel(GSLog.DEBUG))
this.lu.logDebug("Conflict source: " + conflicts[currentChangeConflict.ctype].source + ", itemSysId: " + itemSysId);
// Not registered this conflict for the itemSysId (change or schedule) or it is for the cmdb_ci referenced by the source, we should capture this conflict instead
if (!conflicts[currentChangeConflict.ctype].items[itemSysId] || (this.sourceRecordCISysId && this.sourceRecordCISysId === currentChangeConflict.configurationItemId)) {
conflicts[currentChangeConflict.ctype].items[itemSysId] = {
configuration_item: currentChangeConflict.configurationItemId,
change: currentChangeConflict.changeId,
type: currentChangeConflict.ctype,
conflicting_change: currentChangeConflict.conflictingChangeId,
related_configuration_item: currentChangeConflict.relatedCi,
schedule: currentChangeConflict.scheduleId,
impacted_service: currentChangeConflict.impactedService
};
}
// Need to ensure this counter is incremented for each considered conflict
this.savedCount++;
}
}, this);
if (this.lu.atLevel(GSLog.DEBUG))
this.lu.logDebug("conflicts populated: " + JSON.stringify(conflicts, 3,3,3));
// Save consolidated conflicts
var conflictGR = new GlideRecord(ChangeConflictHandler.CONFLICT);
Object.keys(conflicts).forEach(function(type) {
Object.keys(conflicts[type].items).forEach(function(item) {
this._insertConflict(conflictGR, conflicts[type].items[item]);
}, this);
}, this);
},
_prepareConsolidatedConflictTracker: function(conflictTypes) {
var conflicts = {};
Object.keys(conflictTypes).forEach(function(conflictType) {
// conflictField (source) will be used to derive the conflicting change or schedule that will identify the conflict
var conflictField = conflictType.indexOf("already_scheduled") !== -1 ? "conflictingChangeId" : "scheduleId";
conflicts[conflictType] = {
source: conflictField,
items: {}
};
// Define the relations specific to this type; Parent, Child, etc.
Object.keys(conflictTypes[conflictType]).forEach(function(relation) {
conflicts[conflictTypes[conflictType][relation]] = {
source: conflictField,
items: {}
};
});
});
return conflicts;
},
_insertConflict: function(conflictGR, conflict) {
conflictGR.initialize();
Object.keys(conflict).forEach(function(element) {
conflictGR[element] = conflict[element];
});
conflictGR.insert();
},
type: "ChangeConflictHandlerSNC"
};
Sys ID
ccec495f733600108ef62d2b04f6a761