Name
sn_itom_licensing.ITOMHealthLicenseCounterWithOTOMStore
Description
No description available
Script
gs.include('global.EvtMgmtCommons');
var enableLog = true;
// tables
var HEALTH_CI_TABLE = "itom_lu_health_ci";
var EM_UNIQUE_NODES = "em_unique_nodes";
var LICENSE_CENTRAL_TABLE = "itom_lu_ci_counts";
var SN_OCC_LICENSE_NODES = "sn_occ_license_node";
// constants
var HEALTH_VALUE_STREAM = "Health";
var CMDB_CI = "cmdb_ci";
var CLASS_NAME_DOT_WALK = CMDB_CI + ".sys_class_name";
var DUPLICATE_FIELD_DOT_WALK = CMDB_CI + ".duplicate_of";
var INSTALL_STATUS_DOT_WALK = CMDB_CI + ".install_status";
var DOMAIN_DOT_WALK = CMDB_CI + ".sys_domain";
var NODE = "node";
var OTOM_SKU_TYPE = "otm";
var ITOM_SKU_TYPE = "itom";
// utils
var itomLicensingUtils = new ITOMLicensingUtilsStore();
var metadata = new ITOMLicensingMetaDataStore();
var globalLicensingUtil = new global.UtilScript();
var evtJavaUtil = new global.EMLicensingUtilWrapper();
//global variables
var perfJson = {};
var totalInserted = 0;
gs.include('global.SlowStepJSManager');
var ITOMHealthLicenseCounterWithOTOMStore = Class.create();
ITOMHealthLicenseCounterWithOTOMStore.prototype = {
initialize: function(mode) {
this.isReport = (!gs.nil(mode) && mode == 'report') ? true : false;
this.slowStepsManager = new global.SlowStepJSManager();
var prefix = "ITOM_Licensing_Health_Processor_Slow_Steps ";
var isSlowStepOn = gs.getProperty("enable_analytics_pattern_alert_slow_steps", "true") === 'true';
this.slowStepsManager.initialize(prefix, isSlowStepOn);
this.evtMgmtCommons = new global.EvtMgmtCommons();
this.setValueStreamAndTableName(HEALTH_VALUE_STREAM, HEALTH_CI_TABLE);
},
setValueStreamAndTableName: function(valueStream, valueStreamTableName) {
this.valueStream = valueStream;
this.valueStreamTableName = valueStreamTableName;
},
logMessage: function(message) {
if (enableLog) {
gs.info("ITOMHealthLicenseCounterWithOTOM - " + message);
}
},
deletePreviousCIs: function() {
this.logMessage("Truncating table " + this.valueStreamTableName);
globalLicensingUtil.cleanUpTable(this.valueStreamTableName);
},
populateOccultusCIs: function() {
this.logMessage("Populating Occultus CIs");
var occTotal = 0;
var bulkSize = parseInt(gs.getProperty("evt_mgmt.batchInsertSingleField.bulk_size", 500));
var gr = this.queryForNotNullCis(SN_OCC_LICENSE_NODES);
occTotal += parseInt(this.saveData(gr, bulkSize, true));
gr = this.queryForNullCis(SN_OCC_LICENSE_NODES);
occTotal += parseInt(this.saveData(gr, bulkSize, true));
totalInserted += occTotal;
perfJson.occInserted = occTotal;
this.logMessage("Occultus processed total records: " + occTotal);
},
populateEMCIs: function() {
this.logMessage("Populating EM CIs");
var emTotal = 0;
var bulkSize = parseInt(gs.getProperty("evt_mgmt.batchInsertSingleField.bulk_size", 500));
//get all records from em_unique_nodes table where cmdb not duplicated, cmdb_ci is not null and installed status not in the excluded list of status
var gr = this.queryForNotNullCis(EM_UNIQUE_NODES);
emTotal += parseInt(this.saveData(gr, bulkSize));
gr = this.queryForNullCis(EM_UNIQUE_NODES);
emTotal += parseInt(this.saveData(gr, bulkSize));
totalInserted += emTotal;
perfJson.emInserted = emTotal;
this.logMessage("EM processed total records: " + emTotal);
},
queryForNullCis: function(table) {
var gr = new GlideRecord(table);
gr.addNullQuery(CMDB_CI);
gr.query();
return gr;
},
queryForNotNullCis: function(table) {
var gr = new GlideRecord(table);
gr.addNotNullQuery(CMDB_CI);
gr.addNullQuery(DUPLICATE_FIELD_DOT_WALK);
itomLicensingUtils.addCiStatusQuery(gr, INSTALL_STATUS_DOT_WALK);
gr.query();
return gr;
},
saveData: function(gr, bulkSize, shouldDeduplicate) {
var counter = 0;
var total = 0;
var jsonArr = [];
var node, cmdbCi;
//create array of json objects like these:
//{"cmdb_ci":"12345678901233", "ci_node_hash":"12345678901233","sys_domain":"global"}
//or {"node":"someNode", "ci_node_hash":"someNode_global","sys_domain":"global"}
while (gr.next()) {
var jsonObj = {};
node = gr.node;
cmdbCi = gr.cmdb_ci;
if (global.JSUtil.nil(cmdbCi) && global.JSUtil.nil(node))
continue;
if (!global.JSUtil.nil(node)) {
jsonObj.node = '' + node;
jsonObj.ci_node_hash = node + '@' + gr.node_domain;
jsonObj.sys_domain = '' + gr.node_domain;
}
if (!global.JSUtil.nil(cmdbCi)) {
jsonObj.cmdb_ci = '' + cmdbCi;
jsonObj.ci_node_hash = '' + cmdbCi;
jsonObj.sys_domain = '' + gr.cmdb_ci.sys_domain;
}
jsonArr.push(jsonObj);
counter++;
total++;
if (counter >= bulkSize) {
// 0. Remove duplicate CIs which are already present in the health ci table
if (shouldDeduplicate)
jsonArr = this.deDuplicateCis(jsonArr);
// 1. insert bulk into the target table
evtJavaUtil.batchInsertMultiple(JSON.stringify(jsonArr), this.valueStreamTableName, '');
// 2. set counter to 0
counter = 0;
// 3. re-init json array
jsonArr = [];
}
}
if (counter > 0) {
//insert rest of records in batch
evtJavaUtil.batchInsertMultiple(JSON.stringify(jsonArr), this.valueStreamTableName, '');
}
return total;
},
deDuplicateCis: function(ciList) {
var ciHashMap = {};
var dedupedCiList = [];
for (var i = 0; i < ciList.length; i++)
ciHashMap[ciList[i].ci_node_hash] = ciList[i];
var dedupGr = new GlideRecord(this.valueStreamTableName);
dedupGr.addQuery('ci_node_hash', 'IN', Object.keys(ciHashMap).join(','));
dedupGr.query();
while (dedupGr.next())
delete ciHashMap[dedupGr.getValue('ci_node_hash')];
for (var ciHash in ciHashMap)
dedupedCiList.push(ciHashMap[ciHash]);
return dedupedCiList;
},
populateOICIs: function() {
this.logMessage("Populating OI CIs");
var oiInsertedRecords = evtJavaUtil.populateLicenseCIs();
perfJson.oiInserted = oiInsertedRecords;
this.logMessage("OI processed total records: " + oiInsertedRecords);
},
populateCentralTable: function(skuTypeGr) {
if (this.isReport)
return;
var skuType = skuTypeGr.getValue('sku');
// If skuType is OTOM, but OTOM is not supported, OTOM records shouldn't be written in central tables (itom_lu_ci_counts)
if (skuType == OTOM_SKU_TYPE) {
if (!itomLicensingUtils.isOTDependencyPresent()) return;
}
var skuTypeSysId = skuTypeGr.getValue('sys_id');
this.logMessage("Populating Central table");
var domainList = itomLicensingUtils.getDomains();
// Initialize the json count
var countsJson = itomLicensingUtils.getCountsJsonTemplate(this.valueStream.toLowerCase(), skuType);
// Get a count from each ci_type per Domain
var ciTypeCountsPerDomain = this.getCiCountByTypeAndDomain(skuType);
var countsJsonPerDomain = [];
// Loop over the domains that have CIs, under each domain fill each category with zero or with its number of CIs
for (var i = 0; i < ciTypeCountsPerDomain.length; i++) {
var licCountRec = ciTypeCountsPerDomain[i];
var domainId = licCountRec['domain'];
if (!countsJsonPerDomain[domainId]) {
// Add all categories with zero count under the domain
countsJsonPerDomain[domainId] = itomLicensingUtils.getCountsJsonTemplate(this.valueStream.toLowerCase(), skuType);
}
var ciTypes = Object.keys(licCountRec);
var domainIndex = ciTypes.indexOf('domain');
if (domainIndex != -1)
ciTypes.splice(domainIndex, 1);
var ciTypeToCategory = metadata.getCategories(ciTypes);
var ciTypeKeys = Object.keys(ciTypeToCategory);
var category;
// Update number of CIs under the domain-category
for (var j = 0; j < ciTypeKeys.length; j++) {
category = ciTypeToCategory[ciTypeKeys[j]];
if (category && category != '') {
if (!countsJson.hasOwnProperty(category)) {//in case this category is not part of the licensed categories of Health and the corresponding sku, skip it
continue;
}
if (!countsJsonPerDomain[domainId][category])
countsJsonPerDomain[domainId][category] = 0;
countsJsonPerDomain[domainId][category] = parseInt(countsJsonPerDomain[domainId][category]) + parseInt(ciTypeCountsPerDomain[i][ciTypeKeys[j]]);
}
}
}
//we want to count unknown nodes only for itom, not relevant for otom
if (skuType == ITOM_SKU_TYPE && new global.ArrayUtil().contains(Object.keys(countsJson), metadata.getCategoryNameForUnknown())) {
var unknownCategory = metadata.getCategoryNameForUnknown();
var unknownNodesPerDomain = this.countUnknownDevicesPerDomain();
for (var domainName in unknownNodesPerDomain) {
if (!countsJsonPerDomain[domainName])
countsJsonPerDomain[domainName] = {};
countsJsonPerDomain[domainName][unknownCategory] = parseInt(unknownNodesPerDomain[domainName]);
}
}
var isRemoveNonGlobalZeroRecords = gs.getProperty('sn_itom_licensing.remove_nonglobal_zero_records', 'true');
var categoryAddedToGlobalArr = [];
var globalCategoryCountMap = {};
// Go through the category counts and prepare a json array to insert into central table
//{"category":"x", "value_stream":"Health","count":"y"}
var jsonArr = [];
for (var domain in countsJsonPerDomain) {
var categoryCountKeys = Object.keys(countsJsonPerDomain[domain]);
var domainRecord = domain;
// If domain is not declared, write global instead.
// Done to help the process of "ITOM Licensing Aggregator Store" job to be completed.
if (!new global.ArrayUtil().contains(domainList, domainRecord)) {
this.logMessage("Domain " + domain + " set to global because it is not in domainList:" + JSON.stringify(domainList));
domainRecord = 'global';
}
for (j = 0; j < categoryCountKeys.length; j++) {
category = categoryCountKeys[j];
var count = countsJsonPerDomain[domain][category];
var addRecord = true;
// Check if to remove zero records from domain that is not global
if (isRemoveNonGlobalZeroRecords == 'true') {
if (domain != 'global' && count == 0)
addRecord = false;
}
if (addRecord) {
if (domainRecord == 'global') {
// summarize a map of key:category value: ci counts (var count)
if (new global.ArrayUtil().contains(Object.keys(globalCategoryCountMap), category)) {
globalCategoryCountMap[category] = globalCategoryCountMap[category] + count;
} else {
globalCategoryCountMap[category] = count;
}
} else {
var jsonCountRecord = this.createJsonCountRecord(category, count, domainRecord, skuTypeSysId);
jsonArr.push(jsonCountRecord);
}
}
}
}
// loop over categories of global
var categoryGlobalCountKeys = Object.keys(globalCategoryCountMap);
for (var categoryIndex in categoryGlobalCountKeys) {
var categoryGlobalName = categoryGlobalCountKeys[categoryIndex];
var categoryGlobalCount = globalCategoryCountMap[categoryGlobalName];
var jsonGlobalCountRecord = this.createJsonCountRecord(categoryGlobalName, categoryGlobalCount, 'global', skuTypeSysId);
jsonArr.push(jsonGlobalCountRecord);
// Add the category to the list that used for adding zero records under global
categoryAddedToGlobalArr.push(categoryGlobalName);
}
// insert zero record for each category of the sku, if category not already added
for (var categoryName in countsJson) {
if (!new global.ArrayUtil().contains(categoryAddedToGlobalArr, categoryName)) {
var zeroRecord = this.buildJsonZeroRecord(skuTypeSysId, categoryName);
jsonArr.push(zeroRecord);
}
}
evtJavaUtil.batchInsertMultiple(JSON.stringify(jsonArr), LICENSE_CENTRAL_TABLE, '');
},
createJsonCountRecord: function(category, count, sysDomain, skuTypeSysId) {
var jsonCountRecord = {};
jsonCountRecord.category = category;
jsonCountRecord.count = "" + count;
jsonCountRecord.value_stream = this.valueStream;
jsonCountRecord.is_aggregated = "" + false;
jsonCountRecord.sys_domain = sysDomain;
jsonCountRecord.sku = skuTypeSysId;
return jsonCountRecord;
},
buildJsonZeroRecord: function(skuTypeSysId, category) {
var jsonZeroRecord = {};
jsonZeroRecord.category = category;
jsonZeroRecord.count = "" + 0;
jsonZeroRecord.value_stream = this.valueStream;
jsonZeroRecord.is_aggregated = "" + false;
jsonZeroRecord.sys_domain = 'global';
jsonZeroRecord.sku = skuTypeSysId;
return jsonZeroRecord;
},
countUnknownDevicesPerDomain: function() {
var ga = new GlideAggregate(this.valueStreamTableName);
ga.addNullQuery(CMDB_CI);
ga.addNotNullQuery(NODE);
ga.addAggregate("COUNT", NODE);
ga.groupBy('sys_domain');
ga.query();
var unknownNodeCountPerDomain = {};
while (ga.next()) {
unknownNodeCountPerDomain[ga.getValue('sys_domain')] = ga.getAggregate("COUNT", NODE);
}
return unknownNodeCountPerDomain;
},
addSkuConditions: function(queryRecord, skuType) {
var excludingTableName = "license_exclusion_list";
var excludeGr = new GlideRecord(excludingTableName);
excludeGr.addEncodedQuery("exclusion_reason.value_stream=health^ORexclusion_reason.value_stream=all^exclusion_reason.active=true");
excludeGr.query();
var cisToExclude = [];
while (excludeGr.next()) {
cisToExclude.push(excludeGr.getValue("ci"));
}
// Removing OTOM Related exclusion from exclusion framework. Need to handle in the code for performance.
if (itomLicensingUtils.isOTDependencyPresent()) {
if (skuType == ITOM_SKU_TYPE)
queryRecord.addNullQuery(CMDB_CI + '.cmdb_ot_entity');
if (skuType == OTOM_SKU_TYPE)
queryRecord.addNotNullQuery(CMDB_CI + '.cmdb_ot_entity');
}
if (cisToExclude.length > 0)
queryRecord.addNullQuery(CMDB_CI).addOrCondition(CMDB_CI, "NOT IN", cisToExclude);
},
getCiCountByTypeAndDomain: function(skuType) {
var ga = new GlideAggregate(this.valueStreamTableName);
this.addSkuConditions(ga, skuType);
ga.addNotNullQuery(CMDB_CI);
// only query cis with duplicate_of null
ga.addNullQuery(DUPLICATE_FIELD_DOT_WALK);
// and check for install status
itomLicensingUtils.addCiStatusQuery(ga, INSTALL_STATUS_DOT_WALK);
// prevent empty domain from being fetched, which made each sku-category to be written twice, once always with 0 total count
ga.addNotNullQuery(DOMAIN_DOT_WALK);
ga.addAggregate("COUNT", CMDB_CI);
ga.groupBy(CLASS_NAME_DOT_WALK);
ga.groupBy(DOMAIN_DOT_WALK);
ga.query();
var licenseCountRecords = [];
while (ga.next()) {
var ciTypeAndDomainCounts = {};
var type = ga.getValue(CLASS_NAME_DOT_WALK);
var count = ga.getAggregate("COUNT", CMDB_CI);
var domain = ga.getValue(DOMAIN_DOT_WALK);
ciTypeAndDomainCounts[type] = count;
ciTypeAndDomainCounts['domain'] = domain;
licenseCountRecords.push(ciTypeAndDomainCounts);
}
return licenseCountRecords;
},
checkForCi: function(ciSysId) {
var gr = new GlideRecord(this.valueStreamTableName);
return gr.get(ciSysId);
},
removeExcludedCIs: function() {
this.evtMgmtCommons.removeDoubleCountingOnVirtualAndPhysicalServer(this.valueStreamTableName);
},
// Main function to be called in scheduled job
process: function() {
var pluginManager = new GlidePluginManager();
var start = new Date().getTime();
this.slowStepsManager.setTopic("ITOM Licensing: Health Processor");
this.slowStepsManager.startStep('1: Delete previous CIs');
// delete all previous records
this.deletePreviousCIs();
this.slowStepsManager.startStep('2: Populate EM CIs');
this.populateEMCIs();
this.slowStepsManager.startStep('3: Populate Occultus CIs');
if (pluginManager.isActive('com.sn_occultus_glide'))
this.populateOccultusCIs();
this.slowStepsManager.startStep('4: Populate OI CIs');
if (pluginManager.isActive('com.snc.sa.metric'))
this.populateOICIs();
this.removeExcludedCIsAndPopulateCentralTable(5);
var end = new Date().getTime();
this.evtMgmtCommons.writeToPerfTable("healthLicensingProcess", totalInserted, end - start, perfJson);
},
removeExcludedCIsAndPopulateCentralTable: function(currentStep) {
this.slowStepsManager.startStep(currentStep + ': Remove Excluded CIs');
this.removeExcludedCIs();
this.slowStepsManager.startStep(++currentStep + ': Populate to central table');
var gr = new GlideRecord('itom_lu_sku_type');
gr.query();
while (gr.next())
this.populateCentralTable(gr);
this.slowStepsManager.report();
},
type: 'ITOMHealthLicenseCounterWithOTOMStore'
};
Sys ID
d821eed5538a301046dfddeeff7b12ad