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

Offical Documentation

Official Docs: