Name

sn_agent.AgentDiscoveryHandlerADMHelper

Description

No description available

Script

var AgentDiscoveryHandlerADMHelper = Class.create();
AgentDiscoveryHandlerADMHelper.prototype = {
  initialize: function(tcp_connections, runningProcess, ciSysId) {
      this.running_processes = runningProcess;
      this.connections = tcp_connections;
      this.ciSysId = ciSysId;
  },


  /**
   *
   * This is an exact replica of DiscoveryADMSensor finish block
   * Unlike DiscoveryADMSensor this does not depend on discoverysensor script include
   *
   **/
  addConnectionsAndRelationshipsToCMDB: function(postionInCIJson, hostname, agentGr) {

      // massage our raw connections data a bit...
      this.connections = new global.CookConnections('' + this.ciSysId).process(this.connections);

      // enrich the connections and running processes...
      var epac = new global.EnrichProcessesAndConnections(this);
      epac.process();

      var ciSysId = this.ciSysId;
      var relatedData = {
          running_processes: this.running_processes,
          connections: this.connections,
          getCmdbCi: function() {
              return ciSysId;
          },
      };

      var adm = new global.ApplicationDependencyMapping(relatedData);
      // filter the running processes for only things that we classify...
      if (gs.getProperty('glide.discovery.active_processes_filter', 'false') == 'true' &&
          gs.getProperty('glide.discovery.auto_adm', 'false') != 'true')
          running_processes = adm.matched_processes;

      this.runningProcessReconcile(epac, ciSysId, this.running_processes);

      var relatedListdataObj = {};
      relatedListdataObj['cmdb_tcp'] = {
          data: this.connections,
          refName: 'computer',
          keyName: 'type,ip,port,pid',
          deleteGr: false
      };

      var cmdbGr = new GlideRecord("cmdb_ci");
      cmdbGr.get("sys_id", ciSysId);

      new global.DiscoveryReconciler(cmdbGr, relatedListdataObj).process();

      var applClassificationBehavior = this.getApplicationClassificationBehavior();
      switch (applClassificationBehavior) {
          case 'simple':
              return this.createApplicationCIs(adm.matched_processes, postionInCIJson, hostname);
          case 'full':
              if (!GlidePluginManager.isActive('com.snc.discovery')) {
                  gs.warn("In AgentDiscoveryHandlerADMHelper.addConnectionsAndRelationshipsToCMDB: Cannot trigger application patterns on agent as 'com.snc.discovery' plugin is not activated.");
                  return;
              }
              gs.debug("In AgentDiscoveryHandlerADMHelper.addConnectionsAndRelationshipsToCMDB: Triggering application patterns for CI.sysId = " + ciSysId);
              this.triggerPatternExecution(relatedData, adm, agentGr); //launch Application Patterns
              break;
      }
  },


  /**
   *
   * Need to overwrite this since RunningProcessReconciler needs the Ci Sysid
   * by default EnrichProcessesAndConnections looks at discoverysensor script include
   *
   **/
  runningProcessReconcile: function(epac, ciSysId, running_process) {
      // rebuild the process tree roots
      epac.rps = running_process;
      epac.indexPIDs();
      epac.buildProcessTree();

      // get rid of any nonsense connections...
      epac.noNonsense();

      // flip any "to" connections to "on" connections that need to be flipped
      epac._flipAllConnections();

      // Remove connections if process or any parent process has the same listening port as the process
      // The order is important that this follows _flipAllConnections
      epac._removeConnections();

      // fix up the values in the sensor...
      epac.sensor.running_processes = epac.rps;
      epac.sensor.connections = epac.conns;

      epac.fixProcessPorts();

      // reconcile the running processes...
      var rpr = new global.RunningProcessReconciler(ciSysId, epac.rps, epac.processTreeRoots, epac.byPID);

      rpr.reconcile();

      // now that we've got process sys_ids, fix up our connection references...
      epac.fixConnectionField('sys_id', 'process');

      // deduplicate connections before reconciling...
      epac.dedupeConnections();
  },


  /**
   *
   * Inputs:
   *      - ADM matched processes
   *      - CI reference in IRE payload 
   *      - hostname
   *
   *  Loops through all the ADM matches process and creates Application CI with relationship records
   *
   **/
  createApplicationCIs: function(matched_processes, currentPositioninCIJson, hostname) {

      var pidToPorts = this.getProcessWithAssociatedPorts(this.connections);
      var applicationCIPosition = currentPositioninCIJson;
      var items = [];
      var relations = [];
      var references = [];

      for (var process in matched_processes) {
          var matchedProcess = matched_processes[process];

          if (!matchedProcess.computer) {
              gs.info('No computer field in on the matchedProcess. application CI will not be created');
              continue;
          }

          var applicationCI = {};
          applicationCI['className'] = matchedProcess.classifier.table;
          var applicationCIValues = {};
          applicationCI['values'] = applicationCIValues;

          var tcpPort = pidToPorts[matchedProcess.pid];
          if (typeof tcpPort != 'undefined') {

              if (tcpPort.substring(1).indexOf(':') == tcpPort.length - 2) {
                  tcpPort = tcpPort.substring(1, tcpPort.length - 1);
              }
              applicationCIValues['tcp_port'] = tcpPort;
          }

          applicationCIValues['running_process_command'] = matchedProcess['command'];
          applicationCIValues['running_process_key_parameters'] = matchedProcess['key_parameters'];


          var applicationCIGr = new GlideRecord(matchedProcess.classifier.table);
          var appName = applicationCIGr.getClassDisplayValue();
          appName = appName + '@' + hostname;
          applicationCIValues['name'] = appName;

          // Find the running process sys_id
          var processGr = new GlideRecord('cmdb_running_process');
          processGr.addQuery('computer', matchedProcess.computer);
          processGr.addQuery('pid', matchedProcess.pid);
          processGr.query();
          if (processGr.next())
              applicationCIValues['running_process'] = processGr.getUniqueValue();
          else
              gs.info('process ' + matchedProcess.pid + ' not found on computer ' + matchedProcess.computer);

          items.push(applicationCI);
          relations.push(this.addRelationForPositionsAndType("Runs on::Runs", applicationCIPosition, 0));

          applicationCIPosition++;
      }

      return [items, relations];
  },


  /**
   *
   * helper to add relationship
   *
   **/
  addRelationForPositionsAndType: function(type, parent, child) {
      var relationJsonObj = {};
      relationJsonObj.type = type;
      relationJsonObj.parent = parent;
      relationJsonObj.child = child;

      return relationJsonObj;
  },


  /**
   *
   * Construct PID to Ports mapping
   *
   **/
  getProcessWithAssociatedPorts: function(connections) {
      var pidToPorts = {};

      if (connections != null && typeof connections != 'undefined' && connections.length > 0) {
          for (var idx = 0; idx < connections.length; idx++) {
              var tcp = connections[idx];
              this.addPortToPID(pidToPorts, tcp.pid, tcp.port);
          }
      }

      return pidToPorts;
  },


  /**
   *
   * Format ports with ":" separator.
   * handle multiple ports found for PID
   *
   **/
  addPortToPID: function(pidToPorts, pid, port) {
      var ports = pidToPorts[pid];
      if (typeof ports == 'undefined') {
          pidToPorts[pid] = ':' + port + ':';
      } else {
          if (!ports.includes(':' + port + ':')) {
              pidToPorts[pid] = ports + port + ':';
          }
      }
  },

  /*
   *
   * Trigger pattern execution on agent
   * Input: relatedData - reference to object that has ADM info.
   *        adm - reference to global.ApplicationDependencyMapping 
   *        agentGr - agent GlideRecord
   *
   **/
  triggerPatternExecution: function(relatedData, adm, agentGr) {
      if (!agentGr) {
          gs.error("Error in AgentDiscoveryHandlerADMHelper.triggerPatternExecution: Cannot execute Application Patterns on agents for CI.sysId = " + this.ciSysId + ", 'agentGr' is not defined");
          return;
      }

      try {
          var agentInfo = this.getAgentInfo(agentGr);
          //cannot trigger application patterns if agentId & osType are undefined
          if (Object.keys(agentInfo).length == 0 || !agentInfo.agentId || !agentInfo.osType)
              return;
          var _this = this;
          relatedData.accAgentId = agentInfo.agentId;
          relatedData.getCmdbRecord = function() {
              return _this.getCmdbRecord();
          };

          adm.sensor = relatedData;
          gs.debug("In AgentDiscoveryHandlerADMHelper, adm.sensor.accAgentId =" + adm.sensor.accAgentId);
          adm.initializeForMapping(this.ciSysId);
          adm.matches = adm.get_matches();

          var agentGlobalsHelper = new global.AgentGlobalsHelper();
          agentGlobalsHelper.setOSType(agentInfo.osType); //set necessary global variables
          // relatedData serves as g_sensor mainly to fetch CI info. in ADM script include
          agentGlobalsHelper.setSensor(relatedData);
          agentGlobalsHelper.setSource(agentInfo.ipAddress);

          this.process(adm, agentInfo);
      } catch (e) {
          gs.error("Exception occurred in AgentDiscoveryHandlerADMHelper.triggerPatternExecution for the agent = " + agentInfo.ipAddress + ", error due to :", e);
      }
  },

  getApplicationClassificationBehavior: function() {
      return '' + gs.getProperty('sn_agent.appl_classification_behavior', 'simple');
  },

  /*
   * This method does the actual application dependency mapping:
   * First it classifies the running processes, then it launches probes for the matched processes
   */
  process: function(adm, agentInfo) {
      this.indexByID(); // required to find the matching pid within sn_agent scope
      adm.procByID = this.procByID; // ensures that ADM.putScriptGlobals sets necessary global variables
      this.classified = adm.classify();
      this.launchProbes(this.classified, adm, agentInfo);
  },

  /**
   * Make a map (in this.procByID) of all running processes by ID.
   */
  indexByID: function() {
      this.procByID = {};
      for (var i = 0; i < this.running_processes.length; i++) {
          var proc = this.running_processes[i];
          this.procByID[proc.sys_id] = proc;
      }
  },

  /**
   * Launch probes for matching classified processes as needed.
   */
  launchProbes: function(classified, adm, agentInfo) {
      for (var rp in classified) {
          var match = classified[rp];
          // get the probes we need to trigger; bail out if there weren't any...
          var probes = this.getTriggeredProbes(match, adm);
          if (!probes)
              continue;

          var proc = this.procByID[match.running_process];

          try {
              adm.createPatternProbeForAgent(agentInfo, match, proc, probes);
          } catch (e) {
              gs.error("Exception occurred in AgentDiscoveryHandlerADMHelper.launchProbes for the agent = " + agentInfo.ip_address + ", due to :", e);
          }

      }
  },

  getTriggeredProbes: function(match, adm) {
      // first, figure out which probes, if any, we need to launch...
      var probe_ids = [];
      var pgr = new GlideRecord('discovery_classifier_probe');
      pgr.addQuery('child', '4f64c6389f230200fe2ab0aec32e7068'); // get only horizontal pattern probe related entries
      pgr.addQuery('classy', match.classifier);
      pgr.addActiveQuery();
      pgr.query();
      while (pgr.next()) {
          if (adm.triggerCondition(pgr)) {
              probe_ids.push('' + pgr.child);
          }
      }
      // get out of dodge if there are no probes needed...
      if (probe_ids.length == 0)
          return null;

      // now get a glide record with just these probes in it...
      var rgr = new GlideRecord('discovery_probes');
      rgr.addQuery('sys_id', probe_ids);
      rgr.query();
      return rgr;
  },

  getAgentInfo: function(agentGr) {
      var agent = {};

      if (agentGr.next()) {
          agent.agentId = agentGr.getValue('agent_id');
          agent.ipAddress = agentGr.getValue('ip_address');
          agent.midServerName = this.getMidServerName(agentGr.getValue('mid'));
          agent.osType = this.getOSType();
          agent.name = this.getCmdbRecord().name;
      }

      return agent;
  },

  /**
   * Returns the operating system type (windows, unix, or esx) based on the CI's type...
   * Applicable only for servers at this time, not for Computer 
   */
  getOSType: function() {
      var ci_class = '' + this.getCmdbRecord().sys_class_name;

      if (ci_class == 'cmdb_ci_esx_server')
          return 'esx';

      if (ci_class.indexOf('win_server') >= 0)
          return 'windows';

      if (ci_class == 'cmdb_ci_computer') {
          gs.info("Execution of Application Patterns on agents is not currently supported for endpoints, skipping the CI {sysId=" + this.ciSysId + ", sys_class_name=" + ci_class + "}");
          return;
      }

      return 'unix';
  },

  getCmdbRecord: function() {
      if (!this.validSysId(this.ciSysId))
          return null;

      var gr = new GlideRecord('cmdb_ci');
      gr.addQuery('sys_id', this.ciSysId);
      gr.query();
      if (!gr.next()) {
          gs.info("Unable to retrieve CI record from the database.");
          return null;
      }

      return gr;
  },

  validSysId: function(sysId) {
      return !gs.nil(sysId) && /^[\dA-F]{32}$/i.test(sysId);
  },


  getMidServerName: function(midSysId) {
      var midGr = new GlideRecord('ecc_agent');
      if (midGr.get('sys_id', midSysId)) {
          return midGr.name;
      }
      return "";
  },

  type: 'AgentDiscoveryHandlerADMHelper'
};

Sys ID

df4391a2ff0520108ec45897d53bf1c3

Offical Documentation

Official Docs: