Name
sn_itom_licensing.ITOMLicensingUtilsStore
Description
Utility functions to assist with ITOM Licensing implementations and integration with Usage Analytics
Script
var ITOMLicensingUtilsStore = Class.create();
ITOMLicensingUtilsStore.prototype = {
initialize: function() {
this.api = sn_lef.GlideEntitlement;
this.skuSysId = this._getSKUIDs();
this.globalLicensingUtil = new global.UtilScript();
this.GOVERNANCE_STRING = 'governance';
},
_getSKUIDs: function() {
var res = {};
var gr = new GlideRecord('itom_lu_sku_type');
gr.query();
while (gr.next()) {
res[gr.getValue('sku')] = gr.getUniqueValue();
}
return res;
},
_getSkuType: function(skuId) {
var gr = new GlideRecord("itom_lu_sku_type");
gr.get(skuId);
return gr.getValue("sku");
},
getValueStreams: function() {
var result = [];
var gr = new GlideRecord('itom_lu_bundle_mappings');
gr.query();
while (gr.next()) {
var vs = gr.getValue('value_stream');
vs = vs.split(",");
vs.forEach(function(obj) {
obj = this._localizationSupportForValueStreamName(obj);
if (result.indexOf(obj) == -1) {
result.push(obj);
}
}.bind(this));
}
return result;
},
getOptimizationVSLabel: function() {
return "Optimization";
},
getVisibilityVSLabel: function() {
return "Visibility";
},
getHealthVSLabel: function() {
return "Health";
},
getHLAVSLabel: function() {
return "HLA";
},
getDEXVSLabel: function() {
return "DEX";
},
// Returns map of categories to number of devices per subscription unit.
// Example output: {"Servers": "1", "Containers": "3", "PaaS": "3", "Unresolved monitored objects": "1"}
getCategory2Ratio: function(skuType) {
var licenseInfoJson = this._getItomLicenseInfo();
var suRatio = {};
if (!licenseInfoJson.length)
return {};
if (skuType) {
licenseInfoJson.forEach(function(obj) {
if ((skuType == 'otm' && obj.app_bundle.indexOf('otm') != -1) || (skuType == 'itom' && obj.app_bundle.indexOf('otm') == -1)) {
var catRatio = obj.su_ratio;
Object.keys(catRatio).forEach(function(key) {
if (!suRatio.hasOwnProperty(key)) {
suRatio[key] = catRatio[key];
}
});
}
});
} else {
licenseInfoJson.forEach(function(obj) {
var catRatio = obj.su_ratio;
Object.keys(catRatio).forEach(function(key) {
if (!suRatio.hasOwnProperty(key)) {
suRatio[key] = catRatio[key];
}
});
});
}
return suRatio;
},
getCategories: function() {
var category2Ratio = this.getCategory2Ratio();
return Object.keys(category2Ratio);
},
isLegacyLicenseModel: function() {
if (this.isNewLicenseModel())
return false;
return !(!this._getItomLegacyLicenseInfo().length);
},
isNewLicenseModel: function() {
return !(!this._getItomLicenseInfo().length);
},
_getItomLegacyLicenseInfo: function() {
var licenseInfo = this.api.getItomLegacyLicenseInfo();
if (!licenseInfo)
return [];
return JSON.parse(licenseInfo);
},
// Returns template for teams to use in their CI counting jobs.
// The template is a JSON object that maps each category to 0.
// Categories are aligned with the data in itom_lu_metadata table.
// Example output: {"Servers": 0, "Containers": 0, "PaaS": 0, "Unresolved monitored objects": 0}
getCountsJsonTemplate: function(valueStream, skuType) {
// It will return the first record irrespective of Value Stream if valueStream and skuType is not defined
if (!valueStream && !skuType)
var categories = new sn_itom_licensing.ITOMLicensingMetaDataStore().getCategoryNames();
else if (!skuType)
var categories = new sn_itom_licensing.ITOMLicensingMetaDataStore().getCategoryNamesBasedonValueStream(valueStream.toLowerCase(), 'itom');
else
var categories = new sn_itom_licensing.ITOMLicensingMetaDataStore().getCategoryNamesBasedonValueStream(valueStream.toLowerCase(), skuType);
var category2Count = {};
for (var i = 0; i < categories.length; i++) {
var category = categories[i];
category2Count[category] = 0;
}
return category2Count;
},
// Returns purchased count for the given skuId.
getPurchasedCount: function(skuId) {
var licenseInfo = this._getItomLicenseInfo();
if (!licenseInfo.length)
return 0;
for (var i = 0; i < licenseInfo.length; i++) {
var singleLicenseInfo = licenseInfo[i];
var license = singleLicenseInfo.app_bundle + '';
if (skuId == license)
return parseInt(singleLicenseInfo.purchased_count);
}
return 0;
},
// add discovery source
addDiscoverySource: function(source) {
var productCountGr = new GlideRecord('itom_lu_discovery_sources');
productCountGr.addQuery('source', source);
productCountGr.query();
if (productCountGr.next())
return productCountGr.getUniqueValue();
productCountGr.initialize();
productCountGr.setValue('source', source);
return productCountGr.insert();
},
// Updates the given product's count (for use in legacy ITOM bundle licensing)
updateProductCount: function(product, count) {
var productCountGr = new GlideRecord('itom_lu_product_count');
productCountGr.addQuery('product', product);
productCountGr.query();
var update = true;
// product should always exist OOTB but just in case ...
if (!productCountGr.next()) {
update = false;
productCountGr = new GlideRecord('itom_lu_product_count');
productCountGr.setValue('product', product);
}
productCountGr.setValue('count', count);
return (update ? productCountGr.update() : productCountGr.insert());
},
ignoreITOMDiscovery: function(skuType) {
if (!skuType)
skuType = 'itom';
var ignoreITOMDiscovery = false;
var instanceSkuList = this._getItomLicenseInfo();
var bundles = new sn_itom_licensing.ITOMLicensingMetaDataStore().getBundleIDfromSkuAndBundleType(skuType, "1")
var VISIBILITY = (skuType == 'itom') ? 'visibility' : 'otm_visibility';
for (var i = 0; i < instanceSkuList.length; i++) {
var sku = instanceSkuList[i];
// ITOM or OTOM Discovery SKU should not be used with visibility a-la-carte or any bundles. Ignore it if this is the case.
if (sku && (sku.app_bundle == VISIBILITY || new global.ArrayUtil().contains(bundles, sku.app_bundle))) {
ignoreITOMDiscovery = true;
}
}
return ignoreITOMDiscovery;
},
isOptV2SKUPresent: function() {
var instanceSkuList = this._getItomLicenseInfo();
for (var i = 0; i < instanceSkuList.length; i++) {
var sku = instanceSkuList[i];
if (sku && (sku.app_bundle == 'optimizationv2' || sku.app_bundle == 'itom_enterprisev2')) {
return true;
}
}
return false;
},
isOTDependencyPresent: function() {
var supportedCMDBVersion = "1.28.0";
var count = 0;
var version = this.getInstalledPluginVersion('sn_cmdb_ci_class');
if (!version)
return false;
var versionArr = version.split('.');
var supportedCMDBVersionArr = supportedCMDBVersion.split('.');
for (var i = 0; i < versionArr.length; i++) {
if (parseInt(versionArr[i]) >= parseInt(supportedCMDBVersionArr[i]))
count++;
}
return count == versionArr.length;
},
getDomains: function() {
var domains = ['global'];
var domainGR = new GlideRecord('domain');
if (domainGR.isValid()) {
domainGR.query();
while (domainGR.next())
domains.push(domainGR.getValue('sys_id'));
}
return domains;
},
// This method will get map with key as domains and value as 'true'
getDomainsMap: function() {
var domainMap = {};
var domainList = this.getDomains();
if( Array.isArray(domainList)){
for (var i=0; i< domainList.length; i++) {
domainMap[domainList[i]] = true;
}
}
return domainMap;
},
_isValustreamSKUPresent: function(valueStream, skuType) {
if (!skuType)
skuType = 'itom';
var bundleMapping = new sn_itom_licensing.ITOMLicensingMetaDataStore().getBundleMapping(skuType);
var instanceSkuList = this._getItomLicenseInfo();
for (var i = 0; i < instanceSkuList.length; i++) {
var sku = instanceSkuList[i];
if (new global.ArrayUtil().contains(bundleMapping[valueStream], sku.app_bundle)) {
return true;
}
}
return false;
},
isDiscoveryPresent: function(skuType) {
return this._isValustreamSKUPresent('discovery', skuType);
},
isVisibilityPresent: function(skuType) {
return this._isValustreamSKUPresent('visibility', skuType);
},
isHealthPresent: function(skuType) {
return this._isValustreamSKUPresent('health', skuType);
},
isOptimizationPresent: function(skuType) {
return this._isValustreamSKUPresent('optimization', skuType);
},
isGovernancePresent: function(skuType) {
return this._isValustreamSKUPresent(this.GOVERNANCE_STRING, skuType);
},
isDEXPresent: function(skuType) {
return this._isValustreamSKUPresent(this.getDEXVSLabel().toLowerCase(), skuType);
},
isHLAPresent: function(skuType) {
return this._isValustreamSKUPresent('health', skuType) && this._isValustreamSKUPresent(this.getHLAVSLabel().toLowerCase(), skuType);
},
getMaxResultsFor: function(valueStream, skuType) {
return parseInt(this._getLicensableCIsTableInfo(valueStream, 'max_results', skuType));
},
getAdditionalFiltersFor: function(valueStream, skuType) {
return this._getLicensableCIsTableInfo(valueStream, 'additional_filters', skuType);
},
_getLicensableCIsTableInfo: function(valueStream, column, skuType) {
if (!skuType)
skuType = 'itom';
var itomLicCIsGR = new GlideRecord('itom_lu_licensable_cis_trigger');
itomLicCIsGR.addQuery('value_stream', valueStream.toLowerCase());
itomLicCIsGR.addQuery('sku', this.skuSysId[skuType]);
itomLicCIsGR.setLimit(1);
itomLicCIsGR.query();
if (itomLicCIsGR.next())
return itomLicCIsGR.getValue(column);
},
getExclusionTableName: function(valueStream, skuType) {
if (valueStream == "Discovery")
return skuType + "_visibility_exclusions"; // visibility and discovery both leverage same exclusion table i.e. itom_visibility_exclusions
return skuType + "_" + valueStream.toLowerCase() + "_exclusions";
},
isThisTableSharedByItomAndOtom: function(tableName) {
// 0c5beb6b53c7601046dfddeeff7b120a sys_id of itom in itom_lu_sku_type table
// b1c40f94c7003010b92c660703c26078 sys_id of otom in itom_lu_sku_type table
var gr = new GlideRecord('itom_lu_category_metadata');
gr.addQuery('table', tableName);
gr.addEncodedQuery('sku_typeLIKE0c5beb6b53c7601046dfddeeff7b120a^sku_typeLIKEb1c40f94c7003010b92c660703c26078');
gr.setLimit(1);
gr.query();
return gr.next();
},
setStatusforListing: function(valueStream, status, skuType) {
var gr = new GlideRecord('itom_lu_licensable_cis_trigger');
if (skuType)
gr.addQuery('sku', this.skuSysId[skuType]);
gr.addQuery('value_stream', valueStream);
gr.query();
if (gr.next())
gr.setValue('status', status);
gr.update();
},
setCompletedStatusforListing: function(valueStream, skuType) {
if (this.isJobCanceled(valueStream, skuType)) {
this.setStatusforListing(valueStream, 'canceled', skuType);
this.setJobCanceledFalse(valueStream, skuType);
} else
this.setStatusforListing(valueStream, 'completed', skuType);
},
isListingJobRunning: function(sysIDs) {
var gr = new GlideRecord('itom_lu_licensable_cis_trigger');
gr.addQuery('status', 'running');
if (sysIDs)
gr.addQuery('sys_id', 'IN', sysIDs);
gr.setLimit(1);
gr.query();
return (gr.canRead() && gr.next());
},
isJobCanceled: function(valueStream, skuType) {
var gr = new GlideRecord('itom_lu_licensable_cis_trigger');
if (skuType)
gr.addQuery('sku', this.skuSysId[skuType]);
gr.addQuery('value_stream', valueStream);
gr.addQuery('is_cancel', 'true');
gr.setLimit(1);
gr.query();
return gr.next();
},
setJobCanceledFalse: function(valueStream, skuType) {
var gr = new GlideRecord('itom_lu_licensable_cis_trigger');
if (skuType)
gr.addQuery('sku', this.skuSysId[skuType]);
gr.addQuery('value_stream', valueStream);
gr.query();
if (gr.next()) {
gr.setValue('is_cancel', 'false');
gr.update();
}
},
/*
This is an utility function to check if the listing job got canceled by customer.
*/
isHealthJobCanceled: function(skuType) {
return this.isJobCanceled('health', skuType);
},
isVisibilityJobCanceled: function(skuType) {
return this.isJobCanceled('visibility', skuType);
},
isOptimizationJobCanceled: function(skuType) {
return this.isJobCanceled('optimization', skuType);
},
isDiscoveryJobCanceled: function(skuType) {
return this.isJobCanceled('discovery', skuType);
},
isGovernanceJobCanceled: function(skuType) {
return this.isJobCanceled(this.GOVERNANCE_STRING, skuType);
},
isHLAJobCanceled: function(skuType) {
return this.isJobCanceled(this.getHLAVSLabel(), skuType);
},
isDEXJobCanceled: function(skuType) {
return this.isJobCanceled(this.getDEXVSLabel, skuType);
},
isOTOMPresent: function() {
return this.isSKUPresent('otm');
},
isSKUPresent: function(sku) {
var instanceSkuList = this._getItomLicenseInfo();
for (var i = 0; i < instanceSkuList.length; i++)
if (instanceSkuList[i].app_bundle.indexOf(sku) != -1)
return true;
return false;
},
getSKUSysID: function(sku) {
var gr = new GlideRecord('itom_lu_sku_type');
gr.addQuery('sku', sku);
gr.query();
if (gr.next())
return gr.getUniqueValue();
gs.debug('Invalid SKU Type');
return "";
},
cleanUpCIListingReport: function(valueStream, sku) {
if (!sku)
sku = 'itom';
var gr = new GlideRecord('itom_lu_licensable_cis');
gr.addQuery('value_stream', valueStream);
gr.addQuery('sku', this.skuSysId[sku]);
gr.query();
gr.deleteMultiple();
},
cleanUpTemporaryData: function() {
var gr = new GlideRecord('visibility_lu_temp');
gr.query();
gr.deleteMultiple();
},
addExclusionCondition: function(gr, valueStream, sku, category) {
var exclusionTable = "license_exclusion_list";
var query = "RLQUERY" + exclusionTable + ".ci,=0^exclusion_reason.category=" + category + "^ORexclusion_reason.category=All^exclusion_reason.active=true^exclusion_reason.sku_typeLIKE" + sku + "^exclusion_reason.value_stream=" + valueStream + "^ORexclusion_reason.value_stream=All^ENDRLQUERY";
gr.addQuery(query);
},
addUnclassedOTCondition: function(tableGr) {
// get all child tables of cmdb_ci_ot
var alreadyLicenseCategories = this.globalLicensingUtil.getAllExtensions("cmdb_ci_ot_control");
alreadyLicenseCategories = alreadyLicenseCategories.concat(this.globalLicensingUtil.getAllExtensions("cmdb_ci_ot_field_device"));
alreadyLicenseCategories = alreadyLicenseCategories.concat(this.globalLicensingUtil.getAllExtensions("cmdb_ci_ot_supervisory"));
tableGr.addQuery('sys_class_name', 'NOT IN', alreadyLicenseCategories);
},
getInstalledPluginVersion: function(pluginName) {
var storeAppPluginGR = new GlideRecord('sys_store_app');
storeAppPluginGR.addQuery('scope', pluginName);
storeAppPluginGR.query();
if (storeAppPluginGR.next())
return storeAppPluginGR.getValue('version') + '';
else {
var systemPluginGR = new GlideRecord('v_plugin');
systemPluginGR.addQuery('id', pluginName);
systemPluginGR.query();
if (systemPluginGR.next())
return systemPluginGR.getValue('version') + '';
}
return null;
},
getCommonCategories: function(firstValueStream, secondValueStream, skuType) {
if (!skuType || !firstValueStream || !secondValueStream)
return [];
var categories1 = new sn_itom_licensing.ITOMLicensingMetaDataStore().getCategoryNamesBasedonValueStream(firstValueStream.toLowerCase(), skuType);
var categories2 = new sn_itom_licensing.ITOMLicensingMetaDataStore().getCategoryNamesBasedonValueStream(secondValueStream.toLowerCase(), skuType);
return categories1.filter(function(value) {
return categories2.indexOf(value) > -1;
});
},
//Below are the utilities related to license info
_getItomLicenseInfo: function() {
if (this.licenseInfo)
return this.licenseInfo;
var isCalWithoutSubscriptionEnabled = gs.getProperty('sn_itom_licensing.enable_license_calculation_without_subscription');
this.licenseInfo = JSON.parse(this.api.getUnifiedItomLicenseInfo());
if (isCalWithoutSubscriptionEnabled == 'true') {
this._addDummyLicenseInfo(this.licenseInfo);
}
return this.licenseInfo;
},
_addDummyLicenseInfo: function(licenseInfo) {
var gr = new GlideRecord('itom_lu_bundle_mappings');
gr.addQuery('bundle_type', "0");
gr.query();
var valueStreamsAlreadyPresentInLicenseMap = this._getValueStreamMap(licenseInfo);
var skuTypeSuRatiosMap = this._getSkuTypeSuRatiosMap(licenseInfo);
var otDependencyPresent = this.isOTDependencyPresent();
while (gr.next()) {
var value_stream = this._localizationSupportForValueStreamName(gr.getValue('value_stream'));
if (new global.ArrayUtil().contains(valueStreamsAlreadyPresentInLicenseMap[gr.sku], value_stream) || (!otDependencyPresent && gr.sku == 'b1c40f94c7003010b92c660703c26078') || (value_stream == 'Discovery'))
continue;
var jsonObj = {};
jsonObj.app_bundle = '' + gr.bundle_id;
jsonObj.license_id = '' + gr.bundle_id;
jsonObj.license = '' + value_stream;
jsonObj.purchased_count = 10000;
jsonObj.su_ratio = skuTypeSuRatiosMap['' + gr.sku];
if ('Health' == value_stream || 'HLA' == value_stream) {
var suRatio = {};
var suRatiosFromProperty = this._getCategorySuRatiosFromProperty(gr.getDisplayValue('sku'));
suRatio["Unresolved monitored objects"] = suRatiosFromProperty["Unresolved monitored objects"];
Object.keys(jsonObj.su_ratio).forEach(function(key) {
suRatio[key] = jsonObj.su_ratio[key];
});
jsonObj.su_ratio = suRatio;
}
licenseInfo.push(jsonObj);
}
},
_getValueStreamMap: function(licenseInfo) {
var valueStreamMap = {};
var bundleIds = [];
licenseInfo.forEach(function(obj) {
bundleIds.push(obj.app_bundle);
});
var gr = new GlideRecord('itom_lu_bundle_mappings');
gr.addQuery('bundle_id', 'IN', bundleIds);
gr.query();
while (gr.next()) {
if (!valueStreamMap[gr.sku])
valueStreamMap[gr.sku] = [];
var vs = gr.getValue('value_stream');
vs = vs.split(",");
vs.forEach(function(obj) {
obj = this._localizationSupportForValueStreamName(obj);
if (valueStreamMap[gr.sku].indexOf(obj) == -1)
valueStreamMap[gr.sku].push(obj);
}.bind(this));
}
//Because of mixture of Visibilty & Discovery
//we cannot add Discovery dummy license if Visibility license is present
Object.keys(valueStreamMap).forEach(function(key) {
if (new global.ArrayUtil().contains(valueStreamMap[key], 'Visibility'))
valueStreamMap[key].push('Discovery');
});
return valueStreamMap;
},
_getSkuTypeSuRatiosMap: function(licenseInfo) {
var suRatioMap = {};
var skuTypeGr = new GlideRecord('itom_lu_sku_type');
skuTypeGr.query();
while (skuTypeGr.next()) {
suRatioMap[skuTypeGr.sys_id] = {};
var suRatiosFromProperty = this._getCategorySuRatiosFromProperty(skuTypeGr.sku);
var suRatiosFromLicense = this._getCategorySuRatiosFromLicense(licenseInfo, skuTypeGr.sku);
var gr = new GlideRecord('itom_lu_category_metadata');
gr.addQuery('sku_type', 'CONTAINS', skuTypeGr.sys_id);
gr.query();
while (gr.next()) {
var category = '' + gr.category;
if (suRatiosFromLicense[category]) {
suRatioMap[skuTypeGr.sys_id][category] = suRatiosFromLicense[category];
} else if (suRatiosFromProperty[category]) {
suRatioMap[skuTypeGr.sys_id][category] = suRatiosFromProperty[category];
}
}
}
return suRatioMap;
},
_getCategorySuRatiosFromProperty: function(skuType) {
var categorySuRatios = {};
if (skuType == 'itom') {
categorySuRatios = gs.getProperty('sn_itom_licensing.itom_category_su_ratios_json');
} else if (skuType == 'otm') {
categorySuRatios = gs.getProperty('sn_itom_licensing.otm_category_su_ratios_json');
}
try {
return JSON.parse(categorySuRatios);
} catch (ex) {
gs.error("Unable to parse value of system property of skuType : " + skuType + ", exception :: " + ex);
}
return {};
},
_getCategorySuRatiosFromLicense: function(licenseInfo, skuType) {
var suRatio = {};
for (var i = 0; i < licenseInfo.length; i++)
if (skuType == 'otm' && licenseInfo[i].app_bundle.indexOf('otm') != -1) {
Object.keys(licenseInfo[i].su_ratio).forEach(function(key) {
if (!suRatio.hasOwnProperty(key)) {
suRatio[key] = licenseInfo[i].su_ratio[key];
}
});
} else if (skuType == 'itom' && licenseInfo[i].app_bundle.indexOf('otm') == -1) {
Object.keys(licenseInfo[i].su_ratio).forEach(function(key) {
if (!suRatio.hasOwnProperty(key)) {
suRatio[key] = licenseInfo[i].su_ratio[key];
}
});
}
return suRatio;
},
addCiStatusQuery: function(tableGr, statusColumn) {
var installStatusValuesToExclude = gs.getProperty("sn_itom_licensing.install_status_values_to_exclude", '7,8,100'); // RETIRED, STOLEN, ABSENT
var excludedStatus = installStatusValuesToExclude.replaceAll(' ', '').split(',');
if (excludedStatus.indexOf('NULL') == -1) {
tableGr.addNullQuery(statusColumn).addOrCondition(statusColumn, 'NOT IN', excludedStatus);
} else {
excludedStatus = excludedStatus.filter(function(ele) {
return ele != 'NULL';
});
tableGr.addQuery(statusColumn, 'NOT IN', excludedStatus);
}
},
_localizationSupportForValueStreamName: function(obj) {
obj = obj.trim();
if (obj != 'hla' && obj != 'dex')
obj = obj[0].toUpperCase() + obj.slice(1);
else
obj = obj.toUpperCase();
return obj;
},
type: 'ITOMLicensingUtilsStore'
};
Sys ID
93856bd75375301046dfddeeff7b125b