Name

sn_cmdb_int_util.GlobalApplicationDependencyMappingHelper

Description

No description available

Script

var GlobalApplicationDependencyMappingHelper = Class.create();
GlobalApplicationDependencyMappingHelper.prototype = {
  initialize: function() {
  	this.LOG_ID = 'globalApplicationDependencyMappingHelper []:';
  },
  initializeBySysId: function(ciId) {
      var ciGr = new GlideRecord('cmdb_ci_computer');
      ciGr.get(ciId);
      this.ci_sys_id = '' + ciId;
      this.ci_name = '' + ciGr.name;
      this.relType = new global.DiscoveryFunctions().findOrCreateRelationshipType("cmdb_rel_type", "Depends on::Used by");
      this.classified = {};
      this.procByID = {};
  	this.LOG_ID = this.LOG_ID.replace(/\[.*\]/, "[" + this.ci_sys_id + "]");
  },
  mapCi: function() {

      // build classified (processes) object
      this.classified = this.queryForConnections();

      // build our (potentially quite large) query for connections...
      var gr = this.queryForOtherSide();

      // get all our matched connections...
      var matches = this.matchConnections(gr);

      // if we didn't find any matches, skip the rest of this...
      if (matches.length == 0)
          return;
      for (var i = 0; i < matches.length; i++) {

          var from_appl = this.getApplCIforProcess(matches[i].from.process);

          var to_appl = this.getApplCIforProcess(matches[i].to.process);
          if (!gs.nil(from_appl) && !gs.nil(to_appl)) {
              gs.debug(LOG_ID + " In globalApplicationDependencyMappingHelper: Need to relate appl " + from_appl + " to appl " + to_appl + " on port " + matches[i].to.port);
              this.createOrUpdateRel(from_appl, to_appl, this.relType, matches[i].to.port);
          }

      }
  },
  getApplCIforProcess: function(cmdb_running_processSysId) {

      var agr = new GlideRecord("cmdb_ci_appl");
      var result = null;
      agr.addQuery("running_process", cmdb_running_processSysId);
      agr.query();
      var count = agr.getRowCount();
      if (count == 1) {
          agr.next();
          result = agr.getValue("sys_id");
          gs.info(this.LOG_ID + " In globalApplicationDependencyMappingHelper: Looked for Appl CI of Process " + cmdb_running_processSysId + " - got: " + result);
      }
      return result;
  },
  createOrUpdateRel: function(parent, child, type, port) {
      var rel = new GlideRecord("cmdb_rel_ci");
      rel.addQuery("parent", parent);
      rel.addQuery("child", child);
      rel.addQuery("type", type);
      if (!gs.nil(port)) {
          rel.addQuery("port", port);
      }
      rel.query();
      var count = rel.getRowCount();
      if (count == 0) {
          //create 
          rel.setValue('parent', parent);
          rel.setValue('child', child);
          rel.setValue('type', type);
          if (!gs.nil(port)) {
              rel.setValue("port", port);
          }
          rel.insert();
          gs.info(this.LOG_ID + " In globalApplicationDependencyMappingHelper: createOrUpdateRel created relationship between parent " + parent + " and child " + child);

      } else if (count > 1) {
          gs.warn(this.LOG_ID + " In globalApplicationDependencyMappingHelper: createOrUpdateRel found more than 1 existing rel between parent " + parent + " and child " + child);
      }
  },
  /*
   * Query for the connections found on this computer, returning a GlideRecord instance on the cmdb_tcp table.
   */
  queryForConnections: function() {
      var classified = {},
          grRel = new GlideRecord('cmdb_rel_ci'),
          relType = new global.DiscoveryFunctions().findOrCreateRelationshipType("cmdb_rel_type", "Runs on::Runs");

      grRel.addQuery('child', this.ci_sys_id);
      grRel.addQuery('type', relType);
      grRel.query();
      while (grRel.next()) {
          classified['' + grRel.parent.running_process] = {
              "app": '' + grRel.parent,
              "classifier": '' + grRel.parent.classifier,
              "computer": this.ci_sys_id,
              "running_process": '' + grRel.parent.running_process
          };
          gs.info(this.LOG_ID + " In globalApplicationDependencyMappingHelper: queryForConnections: " + JSON.stringify(classified['' + grRel.parent.running_process]));
      }

      return classified;
  },
  /**
   * Query for the other side of connections found on this computer, returning a GlideRecord instance on the cmdb_tcp table.
   */
  queryForOtherSide: function() {
      var shouldAuto = gs.getProperty('glide.discovery.auto_adm', 'false') == 'true';
      var mapLocal = gs.getProperty('glide.discovery.adm.map_local_connection', 'false') == 'true';

      // iterate over all our connections, adding queries as we go and build our lookup map...
      this.byKey = {};
      this.keySet = [];

      var grTcp = new GlideRecord('cmdb_tcp');
      grTcp.addQuery('computer', this.ci_sys_id);
      grTcp.addQuery('absent', false);
      grTcp.query();
      while (grTcp.next()) {
          var ip = '' + grTcp.ip;


          if (!shouldAuto && !this.classified[grTcp.process])
              continue;

          if (!mapLocal && ip == '127.0.0.1' && !this.classified[grTcp.process])
              continue;

          // we're looking for the opposite type of the current connection, so we flip between the to and on,
          // but we keep the ip and port the same. And obviously, if the ip is a localhost (127.0.0.1) address, then
          // We need to specify the sys_id
          var type = (grTcp.type == 'on') ? 'to' : 'on';
          var matchKey = global.TCPKeyGenerator.getKey(type, ip, this.ci_sys_id, grTcp.port);
          this.keySet.push(matchKey);

          // and map it with a key we can recreate from the results, to find this connection again...
          var fromkey = global.TCPKeyGenerator.getKey(grTcp.type, ip, this.ci_sys_id, grTcp.port);
          this.byKey[fromkey] = '' + grTcp.process; // this used to be an entire 'connections' object entry but looks like we only consume the referenced process sys_id

      }

      // build our (potentially quite large) query for connections...
      var gr = new GlideRecord('cmdb_tcp');
      gr.addNotNullQuery('process');
      gr.addQuery('absent', false);

      gr.addQuery('key', this.keySet);

      // now let's see what we caught in our net...
      gr.query();


      return gr;
  },
  /**
   * Match the connections found on this computer (in this.sensor.connections) with other connections in the database
   * (in the given GlideRecord instance gr), returning a list of matches with info objects whose properties are as follows:
   *
   * info object:
   *   from:
   *     process: sys_id of process (cmdb_running_process) on client side of connection
   *     ci: sys_id of the CI (cmdb_ci) running the client process
   *   to:
   *     process: sys_id of process (cmdb_running_process) on server side of connection
   *     ip: dotted-form v4 IP address of server device OR (if localhost) sys_id of CI (cmdb_ci)
   *     ci: sys_id of the CI (cmdb_ci) running the server process
   *     port: port number (1-65535) of port that server is listening on, and that client connected to
   */
  matchConnections: function(gr) {
      var deduper = {};
      var matches = [];
  	
      while (gr.next()) {
          // build our connection information object...
          var cninfo = {
              from: {
                  ci: null,
                  process: null
              },
              to: {
                  ci: null,
                  process: null,
                  ip: null,
                  port: null
              }
          };
          if (gr.type == 'on') {
              cninfo.to.ci = '' + gr.computer;
              cninfo.to.process = '' + gr.process;
              cninfo.to.ip = '' + gr.ip;
              cninfo.to.port = '' + gr.port;
              cninfo.from.ci = this.ci_sys_id;
              cninfo.from.process = this.byKey[global.TCPKeyGenerator.getKey('to', gr.ip, this.ci_sys_id, gr.port)];
          } else {
              cninfo.from.ci = '' + gr.computer;
              cninfo.from.process = '' + gr.process;
              cninfo.to.ci = this.ci_sys_id;
              cninfo.to.process = this.byKey[global.TCPKeyGenerator.getKey('on', gr.ip, gr.computer, gr.port)];
              cninfo.to.ip = '' + gr.ip;
              cninfo.to.port = '' + gr.port;
          }

          // eliminate one of the pair of connections we'll find if both ends are on this CI (could be any IP)...
          var dd_key = cninfo.to.ci + ':' + cninfo.to.process + ':' + cninfo.to.ip + ':' + cninfo.to.port + ':' +
              cninfo.from.ci + ':' + cninfo.from.process;
          if (deduper[dd_key])
              continue;
          deduper[dd_key] = true;

          // it's a real match, so add it to our results...
          matches.push(cninfo);
      }

      return matches;
  },
  type: 'GlobalApplicationDependencyMappingHelper'
};

Sys ID

1ec7505a77502110258d234468106147

Offical Documentation

Official Docs: