Name

global.RunningProcessReconciler

Description

Reconciles discovered running processes with the running processes in the database. Because each running process contains a reference to its parent, this reconciler must reconcile the records from the root(s) of the tree of running process down toward the leaves to ensure that the parent s sys_id is known before any given record is reconciled.

Script

// Discovery

var RunningProcessReconciler = Class.create();
RunningProcessReconciler.prototype = {
  initialize: function(computer, rps, roots, byPID) {
  	this.computer = computer;
  	this.rps = rps;
  	this.byPID = byPID;

  	this._load_db_rps();
  },

  /**
   * Reconciles this instance's running processes (in this.rps) against the existing database records.
   * The reconciliation is done by recursing toward the process "leaves" from the process tree roots
   * to ensure that references to parents already have a known parent sys_id.
   */
  reconcile: function() {
  	this._reconcileDFS();

  	// now update all the records in this.db_rps that have changed...
  	var absent_procs = [];
  	for (var key in this.db_rps)
  		absent_procs = absent_procs.concat(this.db_rps[key]);

  	while (absent_procs.length)
  		updateAbsent(absent_procs.splice(0, 100));

  	function updateAbsent(toUpdate) {
  		var mu = new GlideMultipleUpdate('cmdb_running_process');
  		mu.addSetQuery('sys_id', GlideRhinoHelper.getListFromRhino(toUpdate));
  		mu.addQuery('absent', false);
  		mu.setValue('absent', 'true');
  		mu.setValue('sys_updated_on', gs.nowNoTZ());
  		mu.execute();

  		// event to update related application CI records to absent
  		// other applications that rely on running processes may also have a script action defined
  		gs.eventQueue("running.process.absent", null, JSON.stringify(toUpdate));
  	}
  },

  _reconcileDFS: function() {
  	var _this = this;

  	_this.rps.forEach(writeProcess);

  	function writeProcess(proc) {
  		var parent, ds_key, existing_rec_sys_id;

  		if (proc.sys_id || proc.alreadySeen)
  			return;

  		// We create synthetic processes that could have circular parent
  		// references - it's possible for a process's child to also be
  		// its parent.  This flag is used to avoid infinite recursion in
  		// this situation.
  		proc.alreadySeen = 1;
  		parent = _this.byPID[proc.ppid];
  		if (parent) {
  			// Make sure I've written my parent so I can set the reference
  			writeProcess(parent);
  			proc.parent = parent.sys_id;
  		}

  		proc.computer = _this.computer;
  		ds_key = proc.command + ':::' + proc.key_parameters;
  		existing_rec_sys_id = _this.db_rps[ds_key] && _this.db_rps[ds_key].pop();
  		if (!existing_rec_sys_id)
  			proc.sys_id = _this.insert(proc);
  		else
  			_this.update(existing_rec_sys_id, proc);
  	}
  },

  /*
   * Inserts the given running process record, returning the new sys_id.
   */
  insert: function(proc) {
  	// set up to insert a new database record...
  	var gr = new GlideRecord('cmdb_running_process');
  	gr.initialize();

  	// copy all the fields from the given discovered data object...
  	for (var field in proc)
  		if (field.indexOf('_') != 0)
  			gr[field] = proc[field];

  	// set the computer reference...
  	gr.computer = this.computer;
  	gr.absent = 'false';

  	// insert into the database, then keep track of it internally...
  	return '' + gr.insert();
  },

  /*
   * Updates the fields in the given database info object with the fields in the given discovered info object.
   */
  update: function(existing_rec_sys_id, ds_proc) {
  	var gr = new GlideRecord('cmdb_running_process');
  	if (existing_rec_sys_id)
  		gr.get('sys_id', existing_rec_sys_id);

  	// copy all the fields from ds_proc to the record
  	for (var field in ds_proc)
  		if (field.indexOf('_') != 0)
  			gr[field] = ds_proc[field];

  	// make sure that absent is set to false...
  	gr.absent = 'false';

  	// set the sys_id for our discovered data...
  	ds_proc.sys_id = existing_rec_sys_id;

  	gr.update();
  },

  /*
   * Load a map existing running process records. The key for the map is "command:::key_parameters", and
   * the values are maps of record properties. Note that this map includes entries that may be marked as
   * "absent" in the database.
   */
  _load_db_rps: function() {

  	var key,
  		gr = new GlideRecord('cmdb_running_process');

  	this.db_rps = {};

  	gr.addQuery('computer', this.computer);
  	gr.query();

  	while (gr.next()) {
  		key = gr.command + ':::' + gr.key_parameters;
  		this.db_rps[key] = this.db_rps[key] || [ ];
  		this.db_rps[key].push('' + gr.sys_id);
  	}
  },

  type: 'RunningProcessReconciler'
};

Sys ID

a61248029731300010cb1bd74b297525

Offical Documentation

Official Docs: