Name

global.DiscoveryQuickDiagnostics

Description

No description available

Script

/**
* Provides AJAX controller methods for the MID log and customer update pages
*/
var DiscoveryQuickDiagnostics = Class.create();

(function() {

var ajaxProcessor,
  prototype = {
  	getModifiedScripts: getModifiedScripts,
  	getDiffUrl: { fn: getDiffUrl, args: [ 'sysId', 'sysClass' ] },
  	getMidLog: { fn: getMidLog, args: [ 'which' ] },
  	grabLogs: { fn: grabLogs, args: [ 'which' ] },
  	getDiscoEccRecs: { fn: getDiscoEccRecs, args: [ 'discoStatus' ] },
  	type: 'DiscoveryQuickDiagnostics'
  };

Object.keys(prototype).forEach(wrapFunction);

DiscoveryQuickDiagnostics.prototype = Object.extendsObject(AbstractAjaxProcessor, prototype);

// Get the list of ECC queue output records for a given discovery status
///////////////////////////////////////////////////////////////////////////////////
function getDiscoEccRecs(status) {
  var gr = new GlideRecord('ecc_queue'),
  	result = [ ];

  gr.addQuery('agent_correlator', status);
  gr.addQuery('queue', 'output');
  gr.query();
  while (gr.next())
  	result.push(gr.sys_id + '');
  return { answer: result };
}

// Re-grab logs from all MID servers that match the filter
///////////////////////////////////////////////////////////////////////////////////
function grabLogs(which) {
  var gr, name, midName, alert,
  	mids = { },
  	include = which.include,
  	exclude = which.exclude,
  	midmanage = new MIDServerManage();

  // Create a map of the MID servers from which we're going to grab logs
  include.ecc_agentName.forEach(function(name) { mids[name] = 1; });

  // Excluding some MID server(s) implies that all others should be included
  if (exclude.ecc_agentName.length || !include.ecc_agentName.length) {
  	gr = new GlideRecord('ecc_agent');
  	gr.query();
  	while (gr.next()) {
  		name = gr.name + '';
  		if (exclude.ecc_agentName.indexOf(name) == -1)
  			mids[name] = 1;
  	}
  }

  // Add MID servers for specific ECC queue records
  include.ecc_queue.forEach(function(sysId) {
  	gr = new GlideRecord('ecc_queue');
  	if (sysId)
  		gr.get('sys_id', sysId);
  	midName = gr.agent + '';
  	midName = midName.substr(11);  // Remove "mid.server."
  	mids[midName] = 1;
  });

  // Add MID servers used by discovery_status records
  include.discovery_status.forEach(function(sysId) {
  	gr = new GlideRecord('ecc_queue');
  	gr.addQuery('agent_correlator', sysId);
  	gr.query();
  	while (gr.next()) {
  		midName = gr.agent + '';
  		midName = midName.substr(11);  // Remove "mid.server."
  		mids[midName] = 1;
  	}
  });

  // Grab the logs for all the MIDs we found
  mids = Object.keys(mids);

  // PRB1374206: Limit to 6 MIDs to avoid semaphore exhaustion.
  // I chose 6 because it will leave some capacity available on 2 node instances.
  if (mids.length > 6) {
  	mids.length = 6;
  	alert = 'Fetching logs from a maximum of 6 MIDs: ' + mids.join(', ');
  }

  mids.forEach(function(name) {
  	name = name.replace(/'/g, "\\'");
  	midmanage.threaddump(name);
  	midmanage.grab_logs(name, 'wrapper.log,agent0.log.0');
  });

  if (alert)
  	return { answer: 'none', alert: alert };
}

///////////////////////////////////////////////////////////////////////////////////
function getMidLog(which) {
  var saGr, sa, agentNames, modified,
  	start = new GlideDateTime(),
  	end = new GlideDateTime(),
  	result = { },
  	gr = new GlideRecord('agent_file');

  if (which.sys_id) {
  	gr.addQuery('sys_id', which.sys_id);
  	if (which.modified) {
  		end.setNumericValue(which.modified);
  		gr.addQuery('sys_updated_on', '!=', end);
  	}
  } else {
  	if (which.excludeRecs.length)
  		gr.addQuery('sys_id', 'NOT IN', which.excludeRecs);

  	// Avoid time zone problems by grabbing logs for an extra day
  	// on each end.
  	start.setNumericValue(which.start - 24 * 60 * 60 * 1000);
  	end.setNumericValue(which.end + 24 * 60 * 60 * 1000);

  	// addEccQueueRestrictions has to happen first because
  	// it may modify both MID servers & start/end dates.
  	addEccQueueRestrictions();
  	addMidRestrictions();
  	addDateRestrictions();
  	addFileRestrictions();
  }

  gr.setLimit(1);
  gr.query();
  if (!gr.next())
  	return result;

  saGr = new GlideRecord('sys_attachment');
  saGr.addQuery('table_sys_id', gr.sys_id);
  saGr.addQuery('table_name', 'agent_file');
  saGr.addQuery('file_name', 'payload.txt');
  saGr.query();
  if (saGr.next()) {
  	sa = new GlideSysAttachmentInputStream(saGr.sys_id);
  	result.content = new Packages.java.io.ByteArrayOutputStream();
  	sa.writeTo(result.content, 0, 0);
  	result.content.close();
  	result.content = result.content.toString();
  } else
  	result.content = (gr.content || '') + '';

  result.sys_id = gr.sys_id + '';
  result.active = !gr.end_date;
  modified = new GlideDateTime(gr.sys_updated_on);
  result.modified = modified.getNumericValue();
  result.mid = gr.mid_server.name + '';
  result.file = gr.name + '';

  return result;

  function addFileRestrictions() {
  	var include = which.include.file,
  		exclude = which.exclude.file;

  	include.forEach(function(name) { gr.addQuery('file', 'LIKE', name); });
  	exclude.forEach(function(name) { gr.addQuery('file', 'NOT LIKE', name); });
  }

  function addDateRestrictions() {
  	var qc1, qc2;

  	gr.addNotNullQuery('start_date');

  	qc1 = gr.addNullQuery('end_date');
  	qc2 = qc1.addOrCondition('start_date', '<', end);
  	qc2.addCondition('end_date', '>', start);
  }

  function addMidRestrictions() {
  	var qc,
  		include = which.include.ecc_agent,
  		exclude = which.exclude.ecc_agent;

  	if (include.length)
  		qc = gr.addQuery('mid_server', 'IN', include);

  	if (agentNames.length) {
  		qc && qc.addOrCondition('mid_server.name', 'IN', agentNames);
  		qc || gr.addQuery('mid_server.name', 'IN', agentNames);
  	}

  	if (exclude.length)
  		gr.addQuery('mid_server', 'NOT IN', exclude);
  }

  function addEccQueueRestrictions() {
  	var include = which.include,
  		names = { };

  	include.discovery_status.forEach(function(ds) {
  		include.ecc_queue = include.ecc_queue.concat(getDiscoEccRecs(ds).answer);
  	});

  	include.ecc_queue.forEach(function(eccSysId) {
  		var name,
  			gr = new GlideRecord('ecc_queue');

  		if (eccSysId && gr.get('sys_id', eccSysId)) {
  			name = gr.agent.substr(11);  // Remove "mid.server."
  			names[name] = 1;

  			if (gr.sys_created_on < start)
  				start = gr.sys_created_on;

  			if (gr.sys_updated_on > end)
  				end = gr.sys_updated_on;
  		}
  	});

  	agentNames = Object.keys(names);
  }
}

function getDiffUrl(sysId, sysClass) {
  var gr = new GlideRecord('sys_update_version');
  gr.addQuery('name', sysClass + '_' + sysId);
  gr.orderBy('sys_created_on');
  gr.setLimit(1);
  gr.query();
  if (gr.next())
  	return 'merge_form_current_version.do?sysparm_version_id=' + gr.sys_id;
}

function getUpgradeHistories() {
  var sysId,
  	histories = { sysIds: [ ], details: { } },
  	gr = new GlideRecord('sys_upgrade_history');

  gr.addNullQuery('update_set');
  gr.query();
  while (gr.next()) {
  	sysId = gr.sys_id + '';
  	histories.sysIds.push(sysId);
  	histories.details[sysId] = {
  		upgraded: gr.upgrade_finished + '',
  		upgradeName: gr.to_version + ''
  	};
  }
  return histories;
}

function getModifiedScripts() {
  var modified, scriptField, name, tableName, sysId, sysPlugin,
  	roots = { },
  	mods = [ ],
  	sysPluginRegex = new RegExp('<sys_package' + ' display_value="(.*?)" source="(.*?)">'),
  	replaceOnUpgradeRegex = /<sys_replace_on_upgrade>(.*?)<\/sys_replace_on_upgrade>/,
  	upgradeHistories = getUpgradeHistories(),
  	scriptFields = getScriptFields(),
  	gr = new GlideRecord('sys_update_version'),
  	ignoreTables = [ 'sys_dictionary_', 'sys_documentation_', 'sys_ui_', 'u_', 'sys_choice_', 'sc_',
  					'kb_', 'asmt_', 'assessment_', 'em_', 'expert_', 'fx_',
  					'pa_', 'catalog_ui_', 'item_option_', 'sa_', 'sp_', 'sys_number', 'catalog_',
  					'io_set_', 'question_choice', 'sys_app_module', 'sys_db_object', 'sys_app',
  					'sys_grid_', 'sys_transform', 'sys_user', 'sys_event', 'wf_workflow',
  					'sys_security', 'discovery_schedule', 'cmdb_ci_', 'cmn_', 'db_image',
  					'sys_report', 'sys_message', 'discovery_range', 'ecc_agent_ip_range',
  					'discovery_snmp_oid', 'ecc_agent_mib', 'jrobin', 'pc_', 'service_scope',
  					'std_change', 'svc_ci_assoc', 'sys_attach', 'sys_filter', 'sys_index',
  					'ua_table_lic', 'sys_index', 'user_criteria', 'sys_data_source',
  					'scheduled_import_set', 'sys_portal', 'sys_rest_message', 'sys_update_xml',
  					'sysevent', 'sys_wizard' ];

  getExtendedTables(scriptFields);
  for (name in scriptFields) {
  	scriptField = scriptFields[name];
  	scriptField.fields = undefined;
  }

  // sys_update_version has an index on name + state.  name will never be null so checking for
  // not null won't affect the result, but MySQL won't use the index if the query doesn't contain
  // the 1st field in the index.
  // Testing on a customer instance with 6 million records in sys_update_version this query
  // went from taking 240 seconds without the notNullQuery to taking only 40 seconds with it.
  gr.addNotNullQuery('name');
  gr.addQuery('state', 'current');
  gr.addQuery('source', 'NOT IN', upgradeHistories.sysIds);  // array of upgrade history sys_ids
  gr.query();

  while (gr.next()) {
  	if (gr.action + '' == 'DELETE')
  		;		// Figure out if this was an OOTB record

  	tableName = gr.name + '';
  	tableName = tableName.split('_');
  	sysId = tableName.pop();
  	tableName = tableName.join('_');

  	if (ignoreTables.some(function(ignore) { return tableName.startsWith(ignore); }))
  		continue;

  	modified = {
  		//details:
  		//lastOotb
  		//lastOotbOn
  		name: gr.record_name + '',
  		action: gr.action + '',
  		application: gr.application + '',
  		replaceOnUpgrade: getReplaceOnUpgrade(),
  		createdBy: gr.sys_created_by + '',
  		createdOn: gr.sys_created_on + '',
  		type: gr.type + '',
  		updateSetSysId: gr.source + '',
  		updateSetName: gr.source.name + '',
  		sysId: sysId,		// SysId of the modified record
  		sysClass: tableName
  	};

  	try {
  		sysPlugin = undefined;
  		sysPlugin = sysPluginRegex.exec(gr.payload + '');
  	} catch (e) {
  		// I'm not sure why this happens but we sometimes get an exception for 'no default value'
  	}

  	/*		modified.plugin = ' -- none -- ';
  	modified.pluginId = ' -- none -- ';
  	modified.ancestors = ' -- none -- ';
  	modified.rootPlugin = ' -- none -- ';
*/
  	if (sysPlugin) {
  		modified.plugin = sysPlugin[1] || ' -- none -- ';
  		//			modified.pluginId = sysPlugin[2] || ' -- none -- ';
  		roots = getRoot(sysPlugin[2]);
  		//			modified.ancestors = roots.join('<br/>');
  		modified.rootPlugin = roots.pop() || sysPlugin[2];
  	}
  	addDetails(modified);

  	mods.push(modified);
  }

  return { answer: { modified: mods, scriptTables: scriptFields } };

  function getRoot(name) {
  	var gr,
  		ancestors = [ ],
  		depth = 0,
  		current = name;

  	if (!roots.hasOwnProperty(current)) {
  		while (current && depth++ < 10) {
  			gr = new GlideRecord('sys_plugins');
  			gr.addQuery('source', current);
  			gr.query();
  			if (!gr.next())
  				break;
  			current = gr.parent + '';
  			if (current)
  				ancestors.push(current);
  		}
  		roots[name] = ancestors;
  	}

  	return roots[name];
  }

  function addDetails(modified) {
  	var hist,
  		//			detail = 'Last changed: ' + gr.sys_created_on + ' By: ' + gr.sys_created_by + ' Update set: ' + gr.source.name,
  		detail = { lc: gr.sys_created_on + '', b: gr.sys_created_by + '', us: gr.source.name + '' },
  		ootb = new GlideRecord('sys_update_version');

  	ootb.addQuery('name', gr.name + '');
  	ootb.addQuery('source', 'IN', upgradeHistories.sysIds);
  	ootb.orderByDesc('sys_created_on');
  	ootb.setLimit(1);
  	ootb.query();
  	if (ootb.next()) {
  		hist = upgradeHistories.details[ootb.source + ''];
  		modified.lastOotb = hist.upgradeName;
  		modified.lastOotbOn = hist.upgraded;
  		//detail += ', OOTB upgrade "' + hist.upgradeName + '" on ' + hist.upgraded;
  		detail.o = 1;
  		detail.un = hist.upgradeName + '';
  		detail.uo = hist.upgraded + '';
  	}// else
  	//	detail += ', New Record';
  	//detail += ' Replace on upgrade: ' + modified.replaceOnUpgrade;
  	modified.details = detail;
  }

  function getReplaceOnUpgrade() {
  	var updateXml = new GlideRecord('sys_update_xml');
  	if (updateXml.get('name', gr.name + ''))
  		return 'No';
  	return 'Yes';
  }
}

function getCustomerUpdates(from) {
  var scriptTables, qc,
  	gr = new GlideRecord('sys_update_xml');

  if (from == 'tablesWithScript') {
  	scriptTables = Object.keys(getScriptFields());
  	qc = gr.addQuery('name', 'STARTSWITH', scriptFields.pop());
  	scriptTables.forEach(function(name) { qc.addOrCondition('name', 'STARTSWITH', name + '_'); });
  } else if (from == 'discovery') {

  } else if (from == 'custom') {

  }
}

function getParms(parms) {
  var result = { };

  parms.forEach(function(name) { result[name] = ajaxProcessor.getParameter('sysparm_' + name); });

  return result;
}

function getScriptFields() {
  var table, dbGr,
  	scriptFields = { },
  	gr = new GlideRecord("sys_dictionary"),
  	qc = gr.addQuery("internal_type", "CONTAINS" ,"script");

  qc.addOrCondition('type', 'String').addCondition('element', 'script');
  gr.query();

  while (gr.next()) {
  	table = gr.name + '';
  	if (!scriptFields[table]) {
  		dbGr = new GlideRecord('sys_db_object');
  		if (dbGr.get('name', table))
  			scriptFields[table] = { type: dbGr.label + '', name: table, fields: [ ] };
  	}
  	scriptFields[table].fields.push(gr.element + '');
  }

  return scriptFields;
}

function getExtendedTables(scriptFields) {
  var gr, table,
  	list = Object.keys(scriptFields);

  while (list.length) {
  	gr = new GlideRecord('sys_db_object');
  	gr.addQuery('super_class.name', list.pop());
  	gr.query();
  	while (gr.next()) {
  		table = gr.name + '';
  		if (scriptFields[table])
  			continue;
  		scriptFields[gr.name + ''] = { type: gr.label + '', name: table, fields: [ ] };
  	}
  }
}

// Wrap a function for use by AjaxQuery:
// 1. Call the function inside a try/catch
// 2. Extract sysparm_ parameters and pass them as function arguments
// 3. Stringify any results
function wrapFunction(name) {
  var descriptor = prototype[name],
  	fn = descriptor.fn || descriptor,
  	argNames = descriptor.args || [ ];

  if (typeof fn == 'function') {
  	delete prototype[name];
  	prototype['ajaxFunction_' + name] = tryCatch;
  }

  function tryCatch() {
  	try {
  		var args = [ ];

  		ajaxProcessor = this;

  		argNames.forEach(
  			function(arg) {
  				var value = ajaxProcessor.getParameter('sysparm_' + arg);
  				if (value === null)
  					args.push(undefined);
  				else {
  					try {
  						value = value + '';
  						value = JSON.parse(value + '');
  					} catch (e) { }

  					args.push(value);
  				}
  			});

  		var answer = fn.apply(ajaxProcessor, args);
  		if (typeof answer != 'object' || !answer.answer)
  			answer = { answer: answer };

  		return JSON.stringify(answer);
  	}
  	catch (e) {
  		return JSON.stringify({ message: e.toString() + e.stack });
  	}
  }
}

})();

Sys ID

83eff6cd533b2300c2e8ddeeff7b126e

Offical Documentation

Official Docs: