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