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