Name

sn_agent.AgentFeatureRegistry

Description

No description available

Script

var AgentFeatureRegistry = Class.create();
AgentFeatureRegistry.prototype = {
  initialize: function(familyRelease, patchLevel, agentFrameworkVersion) {
      // set these variables to override the instance information parsed from the glide.buildtag
      // familyReleaseOverride must be set to one of the values in the family_version_release choice in sn_agent_feature_registry table
      // the overrides will be used if this.useInstanceVersionOverride is set to true
      // this can be used when the instance information cannot be parsed properly from the glide.buildtag
      this.useInstanceVersionOverride = false;
      this.familyReleaseOverride = '';
      this.patchLevelOverride = 0;

      // default values used for instance information when the glide.buildtag sys_property cannot be found
      // used in dev environments since the glide.buildtag property is not set in dev environments
      // if paris patch 0 is not accurate for the dev environment, then the family release information can be overriden
      // by setting the this.useInstanceVersionOverride, this.familyReleaseOverride, and this.patchLevelOverride variables above
      this.familyReleaseDefault = 'paris';
      this.patchLevelDefault = 0;

      this.populateFamilyReleaseMap();
      this.GLIDE_VERSION_REGEX = /glide-(\S*?)-\d{2}-\d{2}-\d{4}(?:__patch(\d+))?/;

      // Used to compare agent versions
      this.versionComparator = new sn_agent.AgentVersionComparator();

      if (agentFrameworkVersion)
          this.agentFrameworkVersion = agentFrameworkVersion;
      else
          this.agentFrameworkVersion = this.getAgentFrameworkVersion();

      if (familyRelease && patchLevel) {
          this.setInstanceVersionInformation(familyRelease, patchLevel);
      } else
          this.initializeInstanceVersionInformation();
  },

  setInstanceVersionInformation: function(familyRelease, patchLevel) {
      this.familyRelease = familyRelease;
      this.familyReleaseOrder = this.getFamilyReleaseOrder(familyRelease);
      this.patchLevel = patchLevel;
      this.familyReleaseName = familyRelease.charAt(0).toUpperCase() + familyRelease.substring(1);
  },

  /*
   * Sets the following variables:
   * this.familyRelease (string value of the family release), empty string represents no family release information
   * this.familyReleaseOrder (integer value used for comparing releases, ordered defined by this.FAMILY_RELEASE_MAP), 0 represents no family release order information
   * this.patchLevel (integer value used for comparing patch levels), -1 represents no patch level information
   * If the familyReleaseOverride and the patchLevelOverride are set, then the instance version information will be initialized using those values
   * Otherwise, the instance version information is parsed from the glide.buildtag sys_property
   */
  initializeInstanceVersionInformation: function() {
      // use override values if they are set
      if (this.useInstanceVersionOverride) {
          this.setInstanceVersionInformation(this.familyReleaseOverride, this.patchLevelOverride);
          return;
      }

      // attempt to get the instance family release and patch level information from glide.buildtag sys_property
      // glide.buildtag property examples:
      // glide-paris-06-24-2020__patch4-11-25-2020
      // glide-paris-06-24-2020__patch0-hotfix1-07-07-2020_07-17-202
      // glide-quebec-12-09-2020
      var glideBuildTag = gs.getProperty('glide.buildtag', '');
      if (glideBuildTag == '' || glideBuildTag.indexOf('glide-track') > -1) {
          // use default values if we cannot find the glide build tag
          this.setInstanceVersionInformation(this.familyReleaseDefault, this.patchLevelDefault);
          return;
      }

      this.parseInstanceVersionFromGlideBuildTag(glideBuildTag);
  },

  /*
   * Check if the specified feature + version is supported on the specified agent
   */
  isFeatureSupportedOnAgent: function(featureName, version, agentId) {
      var agentExtendedInfoGr = this.getAgentExtendedInfoRecord(agentId);
      if (!agentExtendedInfoGr)
          return false;

      var featureRecord = this.getFeatureRecord(featureName, version);
      if (!featureRecord)
          return false;

      if (!this.featureIsSupportedByInstanceAndAgentFramework(featureRecord))
          return false;

      var minimumAgentVersionRequirement = featureRecord.getValue('min_agent_version');
      var maximumAgentVersionRequirement = featureRecord.getValue('max_agent_version');
      var agentVersion = agentExtendedInfoGr.getValue('agent_version');
      return this.versionMeetsRequirements(agentVersion, minimumAgentVersionRequirement, maximumAgentVersionRequirement);
  },

  /*
   * Returns a comma separated list of agent IDs for the agents that support the specified feature
   */
  getSupportedAgentsForFeature: function(featureName, version) {
      var featureRecord = this.getFeatureRecord(featureName, version);
      if (!featureRecord)
          return [];

      if (!this.featureIsSupportedByInstanceAndAgentFramework(featureRecord))
          return [];

      var minimumAgentVersionRequirement = featureRecord.getValue('min_agent_version');
      var maximumAgentVersionRequirement = featureRecord.getValue('max_agent_version');
      return this.getSupportedAgentsForVersion(minimumAgentVersionRequirement, maximumAgentVersionRequirement);
  },

  getSupportedAgentsForVersion: function(minimumAgentVersionRequirement, maximumAgentVersionRequirement) {
      var supportedAgents = [];
      var agentExtendedInfoGr = new GlideRecord('sn_agent_ci_extended_info');
      agentExtendedInfoGr.query();

      while (agentExtendedInfoGr.next()) {
          var agentId = agentExtendedInfoGr.getValue('agent_id');
          var agentVersion = agentExtendedInfoGr.getValue('agent_version');
          if (this.versionMeetsRequirements(agentVersion, minimumAgentVersionRequirement, maximumAgentVersionRequirement))
              supportedAgents.push(agentId);
      }
      return supportedAgents;
  },

  /*
   * Returns a comma separated list of agent IDs for the agents that do not support the specified feature
   */
  getUnsupportedAgentsForFeature: function(featureName, version) {
      if (this.isFeatureFullySupported(featureName, version))
          return [];

      var featureRecord = this.getFeatureRecord(featureName, version);
      if (!featureRecord || !this.featureIsSupportedByInstanceAndAgentFramework(featureRecord)) {
          // feature is not supported, add all agent ids to list of unsupported agents
          var unsupportedAgents = [];
          var agentExtendedInfoGr = new GlideRecord('sn_agent_ci_extended_info');
          agentExtendedInfoGr.query();
          while (agentExtendedInfoGr.next())
              unsupportedAgents.push(agentExtendedInfoGr.getValue('agent_id'));
          return unsupportedAgents;
      }
      var minimumAgentVersionRequirement = featureRecord.getValue('min_agent_version');
      var maximumAgentVersionRequirement = featureRecord.getValue('max_agent_version');
      return this.getUnsupportedAgentsForVersion(minimumAgentVersionRequirement, maximumAgentVersionRequirement);
  },

  getUnsupportedAgentsForVersion: function(minimumAgentVersionRequirement, maximumAgentVersionRequirement) {
      var unsupportedAgents = [];
      var agentExtendedInfoGr = new GlideRecord('sn_agent_ci_extended_info');
      agentExtendedInfoGr.query();
      while (agentExtendedInfoGr.next()) {
          var agentId = agentExtendedInfoGr.getValue('agent_id');
          var agentVersion = agentExtendedInfoGr.getValue('agent_version');
          if (!this.versionMeetsRequirements(agentVersion, minimumAgentVersionRequirement, maximumAgentVersionRequirement))
              unsupportedAgents.push(agentId);
      }
      return unsupportedAgents;
  },

  getFeatureRecord: function(featureName, version) {
      var featureGr = new GlideRecord('sn_agent_feature_registry');
      featureGr.addQuery('feature_name', featureName);
      featureGr.addQuery('feature_version', version);
      featureGr.query();
      if (!featureGr.next()) {
          gs.warn('getFeatureRecord: could not find feature with name "' + featureName + '" and version "' + version + '"', 'AgentFeatureRegistry');
          return null;
      }

      return featureGr;
  },

  getFeatureRecordBySysId: function(featureSysId) {
      var featureGr = new GlideRecord('sn_agent_feature_registry');
      var found = featureGr.get(featureSysId);
      if (!found) {
          gs.warn('getFeatureRecordBySysId: could not find feature with sys_id "' + featureSysId + '"', 'AgentFeatureRegistry');
          return null;
      }
      return featureGr;
  },

  getAgentExtendedInfoRecord: function(agentId) {
      var agentExtendedInfoGr = new GlideRecord('sn_agent_ci_extended_info');
      agentExtendedInfoGr.addQuery('agent_id', agentId);
      agentExtendedInfoGr.query();
      if (!agentExtendedInfoGr.next()) {
          gs.warn('getAgentExtendedInfoRecord: could not find agent with id "' + agentId + '"', 'AgentFeatureRegistry');
          return null;
      }

      return agentExtendedInfoGr;
  },

  isFeatureFullySupported: function(featureName, version) {
      var featureRecord = this.getFeatureRecord(featureName, version);
      if (!featureRecord)
          return false;

      if (!this.featureIsSupportedByInstanceAndAgentFramework(featureRecord))
          return false;

      return this.allAgentsMeetAgentVersionRequirement(featureRecord);
  },

  getHighestAgentVersion: function() {
      if (this.highestAgentVersion)
          return this.highestAgentVersion;

      var agentExtendedInfoGr = new GlideRecord('sn_agent_ci_extended_info');
      agentExtendedInfoGr.setLimit(1);
      agentExtendedInfoGr.orderByDesc('agent_version');
      agentExtendedInfoGr.query();
      if (!agentExtendedInfoGr.next())
          return null;

      this.highestAgentVersion = agentExtendedInfoGr.getValue('agent_version');
      return this.highestAgentVersion;
  },

  getLowestAgentVersion: function() {
      if (this.lowestAgentVersion)
          return this.lowestAgentVersion;

      var agentExtendedInfoGr = new GlideRecord('sn_agent_ci_extended_info');
      agentExtendedInfoGr.setLimit(1);
      agentExtendedInfoGr.orderBy('agent_version');
      agentExtendedInfoGr.query();
      if (!agentExtendedInfoGr.next())
          return null;

      this.lowestAgentVersion = agentExtendedInfoGr.getValue('agent_version');
      return this.lowestAgentVersion;
  },

  allAgentsMeetAgentVersionRequirement: function(featureRecord) {
      var agentExtendedInfoGr;
      var maximumAgentVersionRequirement = featureRecord.getValue('max_agent_version');
      if (maximumAgentVersionRequirement) {
          // query for the agent with the highest agent version
          var maxAgentVersion = this.getHighestAgentVersion();
          if (!maxAgentVersion)
              return false;

          // return false if maxAgentVersion is greater than (return value 1) maximumAgentVersionRequirement
          if (this.versionComparator.compare(maxAgentVersion, maximumAgentVersionRequirement) == 1)
              return false;
      }
      // query for the agent with the lowest agent version
      var minAgentVersion = this.getLowestAgentVersion();
      if (!minAgentVersion)
          return false;

      // all agents meet the agent version requirement of this feature if the lowest agent version is
      // greater than or equal to the minimum agent version requirement specified by the feature record
      var minimumAgentVersionRequirement = featureRecord.getValue('min_agent_version');
      // return true if minAgentVersion is greater than or equal to (return value 0 or 1) minimumAgentVersionRequirement
      return this.versionComparator.compare(minAgentVersion, minimumAgentVersionRequirement) != -1;
  },

  allAgentsMeetMinRequirement: function(featureRecord) {
      var minAgentVersion = this.getLowestAgentVersion();
      if (!minAgentVersion)
          return false;

      return this.versionMeetsMinRequirement(minAgentVersion, featureRecord.min_agent_version);
  },

  noAgentsMeetAgentVersionRequirement: function(featureRecord) {
      var agentExtendedInfoGr;
      var maximumAgentVersionRequirement = featureRecord.getValue('max_agent_version');
      if (maximumAgentVersionRequirement) {
          // query for the agent with the lowest agent version
          var minAgentVersion = this.getLowestAgentVersion();
          if (!minAgentVersion)
              return true;

          // return true if minAgentVersion is greater than (return value 1) maximumAgentVersionRequirement
          if (this.versionComparator.compare(minAgentVersion, maximumAgentVersionRequirement) == 1)
              return true;
      }
      // query for the agent with the highest agent version
      var maxAgentVersion = this.getHighestAgentVersion();
      if (!maxAgentVersion)
          return true;

      var minimumAgentVersionRequirement = featureRecord.getValue('min_agent_version');
      // return true if minAgentVersion is less than (return value -1) minimumAgentVersionRequirement
      return this.versionComparator.compare(maxAgentVersion, minimumAgentVersionRequirement) == -1;
  },

  versionMeetsMaxRequirement: function(version, maxRequirement) {
      // check to see if we have a max requirement
      // if the version is greater than the max requirement, then we know the requirements aren't met
      if (maxRequirement && (this.versionComparator.compare(version, maxRequirement) == 1))
          // return false if version is greater than (return value 1) maxRequirement
          return false;

      // return true if no max requirement or if the version is lower than or equal to the max
      return true;
  },

  versionMeetsMinRequirement: function(version, minRequirement) {
      // return true if version is greater than or equal to (return value 0 or 1) minRequirement
      return this.versionComparator.compare(version, minRequirement) != -1;
  },

  versionMeetsRequirements: function(version, minRequirement, maxRequirement) {
      return this.versionMeetsMaxRequirement(version, maxRequirement) && this.versionMeetsMinRequirement(version, minRequirement);
  },

  featureIsSupportedByInstanceAndAgentFramework: function(featureRecord) {
      return this.featureIsSupportedByInstance(featureRecord) && this.featureIsSupportedByAgentFramework(featureRecord);
  },

  featureIsSupportedByInstance: function(featureRecord) {
      return this.instanceMeetsMaxRequirement(featureRecord) && this.instanceMeetsMinRequirement(featureRecord);
  },

  instanceMeetsMaxRequirement: function(featureRecord) {
      var familyReleaseMaximumRequirement = featureRecord.getValue('max_family_release');
      var patchLevelMaximumRequirement = featureRecord.getValue('max_patch_level');
      if (familyReleaseMaximumRequirement != null && patchLevelMaximumRequirement != null) {
          var familyReleaseOrderMaximumRequirement = this.getFamilyReleaseOrder(familyReleaseMaximumRequirement);
          if (this.familyReleaseOrder > familyReleaseOrderMaximumRequirement ||
              this.familyReleaseOrder == familyReleaseOrderMaximumRequirement && this.patchLevel > patchLevelMaximumRequirement)
              return false;
      }

      // return true if there are no max requirements
      return true;
  },

  instanceMeetsMinRequirement: function(featureRecord) {
      var familyReleaseMinimumRequirement = featureRecord.getValue('min_family_release');
      var familyReleaseOrderMinimumRequirement = this.getFamilyReleaseOrder(familyReleaseMinimumRequirement);
      var patchLevelMinimumRequirement = featureRecord.getValue('min_patch_level');
      return this.familyReleaseOrder > familyReleaseOrderMinimumRequirement ||
          (this.familyReleaseOrder == familyReleaseOrderMinimumRequirement && this.patchLevel >= patchLevelMinimumRequirement);
  },

  featureIsSupportedByAgentFramework: function(featureRecord) {
      return this.agentFrameworkMeetsMaxRequirement(featureRecord) && this.agentFrameworkMeetsMinRequirement(featureRecord);
  },

  agentFrameworkMeetsMaxRequirement: function(featureRecord) {
      var maxRequirement = featureRecord.getValue('max_acc_f_version');
      return this.versionMeetsMaxRequirement(this.agentFrameworkVersion, maxRequirement);
  },

  agentFrameworkMeetsMinRequirement: function(featureRecord) {
      var minRequirement = featureRecord.getValue('min_acc_f_version');
      return this.versionMeetsMinRequirement(this.agentFrameworkVersion, minRequirement);
  },

  /*
   * Maps the family release names to its index in the family release order
   * e.g. orlando -> 0, paris -> 1, quebec -> 2, etc.
   * This allows for the script to determine the order of the family releases
   * The map is populated by obtaining the sequence of the family releases in the
   * sn_agent_feature_registry min_family_release choice field
   */
  populateFamilyReleaseMap: function() {
      this.FAMILY_RELEASE_MAP = {};
      var sysChoiceGr = new GlideRecord('sys_choice');
      sysChoiceGr.addQuery('name', 'sn_agent_feature_registry');
      sysChoiceGr.addQuery('element', 'min_family_release');
      sysChoiceGr.query();
      while (sysChoiceGr.next()) {
          var releaseName = sysChoiceGr.getValue('value');
          var sequence = parseInt(sysChoiceGr.getValue('sequence'));
          this.FAMILY_RELEASE_MAP[releaseName] = sequence;
      }
  },

  getFamilyReleaseOrder: function(familyRelease) {
      if (!this.FAMILY_RELEASE_MAP)
          throw 'family release map has not been populated yet';

      if (!this.FAMILY_RELEASE_MAP.hasOwnProperty(familyRelease))
          throw 'could not find specified family release "' + familyRelease + '" in the family release map';

      return this.FAMILY_RELEASE_MAP[familyRelease];
  },

  parseInstanceVersionFromGlideBuildTag: function(glideBuildTag) {
      var matches = this.GLIDE_VERSION_REGEX.exec(glideBuildTag);
      if (!matches || matches.length < 2)
          throw 'could not parse family release and patch level from glide.buildtag';

      var familyRelease = matches[1];
      if (matches.length == 3)
          var patchLevelInt = parseInt(matches[2]);

      var patchLevel = patchLevelInt ? patchLevelInt : 0;
      this.setInstanceVersionInformation(familyRelease, patchLevel);
  },

  getAgentFrameworkVersion: function() {
      var storeAppGr = new GlideRecord('sys_store_app');
      storeAppGr.addQuery('name', 'Agent Client Collector Framework');
      storeAppGr.query();
      if (!storeAppGr.next())
          throw 'could not find store app record with name "Agent Client Collector Framework"';

      var version = storeAppGr.getValue('version');

      if (!version)
          throw 'could not obtain version from "Agent Client Collector Framework" store app record';

      if (version.endsWith('-SNAPSHOT'))
          version = version.substr(0, version.lastIndexOf('-'));

      return version;
  },

  type: 'AgentFeatureRegistry'
};

Sys ID

b13fb7307365e0102535b7385ef6a704

Offical Documentation

Official Docs: