Name
global.CommonMIDServerSelector
Description
Finds a MID server based on capabilities and target IP address.
Script
var CommonMIDServerSelector = Class.create();
CommonMIDServerSelector.prototype = {
initialize: function() {
this.overrideValid = GlideProperties.get("glide.ecc_agent.validated.override", "false");
this.useLegacy = GlideProperties.get("sa.mapping.legacy_mid_selection", "false");
this.mm = new SNC.MidManager();
this.cf = new FindMidCapabiltiesByHost();
},
isEmpty: function(str) {
return (!str || 0 === str.length);
},
findAgentForDNS: function(midListToExclude, applicationName) {
if (this.useLegacy == "true")
return this.findAgentForDNSLegacy(midListToExclude);
if (this.isEmpty(applicationName))
applicationName = "ServiceMapping";
if(midListToExclude){
midListToExclude = JSON.parse(midListToExclude);
}
return this.mm.findMidWithExclusions(applicationName, "", "", true, midListToExclude);
},
findAgent: function(target, hostId, applicationName) {
if (this.useLegacy == "true")
return this.findAgentLegacy(target, hostId, applicationName);
return this._findAgentHandler(target, hostId, applicationName);
},
_findAgentHandler: function(target, hostId, applicationName) {
if (this.isEmpty(applicationName))
applicationName = "ServiceMapping";
var capArray = this.isEmpty(hostId) ? [] : this.cf.findMidCapabilties(hostId);
// If one of the capabilties is Cloud Management, use the CMP API to find the correct MID
if (capArray) {
for (var capIndex = 0;capIndex<capArray.length; capIndex++) {
if (capArray[capIndex] == 'Cloud Management') {
gs.debug("CommonMidServerSelector._findAgentHandler: Cloud Management capability required");
return this.findMidForCloud(hostId , applicationName);
}
}
}
return this.mm.findMid(applicationName, target, capArray.toString(), true);
},
findAgentCandidates: function(target, hostId, applicationName, cap) {
if (this.useLegacy == "true"){
return this.findAgentLegacyTest(target, hostId, applicationName);
}
if (this.isEmpty(applicationName))
applicationName = "ServiceMapping";
var capArray = this.isEmpty(cap) ? [] : [cap];
return this.mm.getMidCandidates(applicationName, target, capArray.toString(), true);
},
findAgentForDNSLegacy: function(midListToExclude) {
var midList = [];
var gr = this.getEccAgentRecord();
if(midListToExclude){
midListToExclude = JSON.parse(midListToExclude);
gr.addQuery('name', 'NOT IN', midListToExclude);
}
gr.query();
var defaultMidServer = GlideProperties.get("mid.server.sm_default");
while (gr.next() ) {
var name = gr.getValue('name');
if (name == defaultMidServer)
return defaultMidServer;
midList.push(name);
}
if (midList.length > 0)
return midList[0];
return null;
},
//Now legacy mode must support ALL application and ALL IP range
//MID with ALL ip range is treated as one that has no range, and can serve all ip addresses
findAgentLegacy: function(target, hostId, applicationName) {
var applicationId = this.isEmpty(applicationName) ? ' ' : this.getApplicationId(applicationName);
var midsForApplication = this.findMidsForApplication(applicationId);
// If there's at least one MID with an IP range defined limit MID candidates by searching MID by IP ranges and pick one MID randomly and return it
if (!this.isValidIPAddress(target)) {
gs.info("************* Target ip is:" + target +"*************");
if (target === null) // serverless case
return this._findAgentHandler(target, hostId, applicationName);
return null;
}
var allIpRangeSysId = this.getALLipRangeSysId();
var midIdsWithALLrange = this.isEmpty(allIpRangeSysId) ? [] : this.getMidsWithALLipRange(allIpRangeSysId);
var only_mids_with_ranges = this.findMidsWithIpRange(midIdsWithALLrange);
var midIdsWithRanges = [];
var midIdsWithNoRanges = [];
var gr = this.getEccAgentRecord();
if (midsForApplication.length > 0)
gr.addQuery('sys_id', midsForApplication);
gr.query();
var midServerRangesDB = SncMIDServerRangesDB;
while (gr.next()) {
var agentId = gr.getValue('sys_id');
if (only_mids_with_ranges) {
if (midServerRangesDB.inRanges(target, agentId))
midIdsWithRanges.push(agentId);
} else {
if (!this.isEmpty(allIpRangeSysId) && this.isMidHasALLipRange(agentId, allIpRangeSysId))
midIdsWithNoRanges.push(agentId);
else if (midServerRangesDB.noRanges(agentId))
midIdsWithNoRanges.push(agentId);
}
}
if (midIdsWithRanges.length > 0)
return this.selectRandomMid(midIdsWithRanges);
// If there is a default MID, return this MID
var mid = this.findDefaultMid();
if (mid)
return mid;
// If there is no default mid and all the MIDs have no IP ranges, pick one MID randomly
if (midIdsWithNoRanges.length > 0){
return this.selectRandomMid(midIdsWithNoRanges);
}
return null;
},
findAgentLegacyTest: function(target, hostId, applicationName) {
var applicationId = this.isEmpty(applicationName) ? ' ' : this.getApplicationId(applicationName);
var midsForApplication = this.findMidsForApplication(applicationId);
// If there's at least one MID with an IP range defined limit MID candidates by searching MID by IP ranges and pick one MID randomly and return it
if (!this.isValidIPAddress(target))
return null;
var allIpRangeSysId = this.getALLipRangeSysId();
var midIdsWithALLrange = this.isEmpty(allIpRangeSysId) ? [] : this.getMidsWithALLipRange(allIpRangeSysId);
var only_mids_with_ranges = this.findMidsWithIpRange(midIdsWithALLrange);
var midIdsWithRanges = [];
var midIdsWithNoRanges = [];
var gr = this.getEccAgentRecord();
if (midsForApplication.length > 0)
gr.addQuery('sys_id', midsForApplication);
gr.query();
var midServerRangesDB = SncMIDServerRangesDB;
while (gr.next()) {
var agentId = gr.getValue('sys_id');
if (only_mids_with_ranges) {
if (midServerRangesDB.inRanges(target, agentId))
midIdsWithRanges.push(gr.getValue('name') + " : " + agentId);
} else {
if (!this.isEmpty(allIpRangeSysId) && this.isMidHasALLipRange(agentId, allIpRangeSysId))
midIdsWithNoRanges.push(gr.getValue('name') + " : " + agentId);
else if (midServerRangesDB.noRanges(agentId))
midIdsWithNoRanges.push(gr.getValue('name') + " : " + agentId);
}
}
if (midIdsWithRanges.length > 0)
return this.mm.convertMidCandidatesToJsonMap(midIdsWithRanges);
// If there is a default MID, return this MID
var mid = this.findDefaultMid();
if (mid){
var midArr = [];
midArr.push(default_sm_mid + " : " + mid);
return this.mm.convertMidCandidatesToJsonMap(midIdsWithRanges);
}
// If there is no default mid and all the MIDs have no IP ranges, pick one MID randomly
if (midIdsWithNoRanges.length > 0)
return this.mm.convertMidCandidatesToJsonMap(midIdsWithNoRanges);
return null;
},
getALLipRangeSysId : function () {
var gr = new GlideRecord('ecc_agent_ip_range');
gr.addQuery('name', 'ALL');
gr.query();
return gr.next() ? gr.getUniqueValue() : '';
},
isMidHasALLipRange : function (agent, allIpRangeSysId) {
var gr = new GlideRecord('ecc_agent_ip_range_m2m');
gr.addQuery('agent', agent);
gr.addQuery('ip_range', allIpRangeSysId);
gr.query();
return gr.next();
},
getMidsWithALLipRange : function (allIpRangeSysId) {
var res = [];
var gr = new GlideRecord('ecc_agent_ip_range_m2m');
gr.addQuery('ip_range', allIpRangeSysId);
gr.query();
while(gr.next())
res.push(gr.getValue('agent'));
return res;
},
selectRandomMid: function(midIds) {
var ms = new Date().getMilliseconds();
var index = ms % midIds.length;
var selectedMid = midIds[index];
var gr = new GlideRecord("ecc_agent");
gr.addQuery('sys_id', selectedMid);
gr.query();
if (gr.next())
return gr.getValue('name');
},
getApplicationId: function(applicationName) {
if (this.isEmpty(applicationName))
return null;
var gr = new GlideRecord('ecc_agent_application');
gr.addQuery('name', applicationName);
gr.query();
if (gr.next())
return gr.getValue('sys_id');
return null;
},
getALLapplicationSysId : function () {
var gr = new GlideRecord('ecc_agent_application');
gr.addQuery('name', 'ALL');
gr.query();
return gr.next() ? gr.getUniqueValue() : '';
},
isMidAssignedToAllApplication : function(agent, allApplicationSysId) {
var gr = new GlideRecord('ecc_agent_application_m2m');
gr.addQuery('agent', agent);
gr.addQuery('application', allApplicationSysId);
gr.query();
return gr.next();
},
getMidsWithoutAssignedApps: function() {
var midsWithAssignedApps = [];
var midsWithoutAssignedApps = [];
var allApplicationSysId = this.getALLapplicationSysId();
var gr = new GlideRecord('ecc_agent_application_m2m');
gr.query();
var curMidSysId;
var curApplication;
while(gr.next()) {
curMidSysId = gr.getValue('agent');
if (!this.isEmpty(allApplicationSysId) && this.isMidAssignedToAllApplication(curMidSysId, allApplicationSysId))
midsWithoutAssignedApps.push(curMidSysId);
else
midsWithAssignedApps.push(curMidSysId);
}
gr = this.getEccAgentRecord();
if (midsWithAssignedApps.length > 0)
gr.addQuery('sys_id', 'NOT IN', midsWithAssignedApps);
gr.query();
while(gr.next())
midsWithoutAssignedApps.push(gr.getUniqueValue());
return midsWithoutAssignedApps;
},
findMidsForApplication: function(applicationId) {
var midsForApplication = [];
var midsWithoutAssignedApplication = this.getMidsWithoutAssignedApps();
var gr = new GlideRecord('ecc_agent_application_m2m');
gr.addQuery('application', applicationId);
gr.query();
while (gr.next()){
var agent = gr.getValue('agent');
midsForApplication.push(agent);
}
if (midsForApplication.length == 0)
midsForApplication = midsWithoutAssignedApplication;
// ecc_agent table is domain separated so all the mids we find in this table belong to the right domain
var midsForApplicationForDomain = [];
gr = this.getEccAgentRecord();
if (midsForApplication.length > 0)
gr.addQuery('sys_id', 'IN' ,midsForApplication);
gr.query();
while(gr.next())
midsForApplicationForDomain.push(gr.getValue('sys_id'));
return midsForApplicationForDomain;
},
findMidsWithIpRange: function(midIdsWithALLrange) {
var midServers = [];
// ecc_agent table is domain separated so all the mids we find in this table belong to the right domain
var gr = this.getEccAgentRecord();
if (midIdsWithALLrange.length > 0)
gr.addQuery('sys_id', 'NOT IN', midIdsWithALLrange);
gr.query();
while(gr.next()){
var agent = gr.getValue('sys_id');
midServers.push(agent);
}
gr = new GlideRecord('ecc_agent_ip_range_m2m');
gr.addQuery('agent', midServers);
gr.query();
gr.limit(1);
if (gr.hasNext())
return true;
return false;
},
findDefaultMid: function() {
var defaultMidServer = GlideProperties.get("mid.server.sm_default");
if (!JSUtil.nil(defaultMidServer)){
var gr = this.getEccAgentRecord();
gr.addQuery('name', defaultMidServer);
gr.query();
if (gr.next())
return defaultMidServer;
return null;
}
},
getEccAgentRecord: function() {
var gr = new GlideRecord('ecc_agent');
gr.addQuery('status', 'Up');
if (this.overrideValid == "false")
gr.addQuery('validated', true);
return gr;
},
isValidIPAddress: function(ipAddress) {
var ipAddressUtil = GlideIPAddressUtil;
if (ipAddressUtil.isValid(ipAddress))
return true;
return false;
},
/*
* Find the MID to be used in case of cloud object. Use the CMP API to find the MID
*/
findMidForCloud : function(hostId, applicationName) {
gs.debug("CommonMidServerSelector.findMidForCloud: HostId {0}, Application {1}", hostId, applicationName);
// Find the LDC, as first step for finding the service account
var cmdbGr = new GlideRecord('cmdb_ci');
if (!cmdbGr.get(hostId)) {
gs.log('Host ' + hostId + ' not found in the CMDB');
return null;
}
var hostClass = cmdbGr.sys_class_name;
var ldc;
if (GlideDBObjectManager.get().isInstanceOf(hostClass,'cmdb_ci_logical_datacenter'))
ldc = hostId;
else {
// Follow hosted-on relation from the hostId to the logical datacenter
var relGr = new GlideRecord('cmdb_rel_ci');
relGr.addQuery('parent', hostId);
relGr.addQuery('type', '5f985e0ec0a8010e00a9714f2a172815'); // Hosted-on
relGr.query();
if (relGr.next())
ldc = relGr.child;
}
if (!ldc) {
gs.log('Failed to locate the logical datacenter of CI ' + hostId);
return null;
}
gs.debug("CommonMidServerSelector.findMidForCloud: found LDC {0}", ldc);
// Now that we got LDC, get the region name
var ldcGr = new GlideRecord('cmdb_ci_logical_datacenter');
if (!ldcGr.get(ldc)) {
gs.log('ldc ' + ldc + ' not found in table cmdb_ci_logical_datacenter');
return null;
}
gs.debug("CommonMidServerSelector.findMidForCloud: LDC {0} is valid", ldc);
// a LDC always has a service account as a parent.. find the service account id for the chosen LDC
var relGr = new GlideRecord('cmdb_rel_ci');
relGr.addQuery('parent', ldc);
relGr.addQuery('type', '5f985e0ec0a8010e00a9714f2a172815'); // Hosted on:: Hosts
relGr.query();
var service_account_id = '';
if (relGr.next()) {
var serviceAccountSysId = relGr.getValue();
var serviceAccountGr = new GlideRecord('cmdb_ci_cloud_service_account');
if (serviceAccountGr.get(serviceAccountSysId)) {
service_account_id = serviceAccountGr.getValue('account_id');
} else {
gs.warn('Could not find a service account : ' + serviceAccountSysId);
}
}
var invocationContext = {};
invocationContext['service_account_id'] = service_account_id;
gs.debug("CommonMidServerSelector.findMidForCloud: Calling CloudMidSelectionApi. LDC region {0}", ldcGr.region);
var cmdMidSelector = new global.CloudMidSelectionApi();
var mid_id = cmdMidSelector.selectMid(applicationName, null, ldcGr.region, JSON.stringify(invocationContext));
if (!mid_id) {
gs.log('No available MID found by CloudMidSelectionApi');
return mid_id;
}
gs.debug("CommonMidServerSelector.findMidForCloud: Found MID {0}. Verifying...", mid_id);
// Find the mid name
var midGr = new GlideRecord('ecc_agent');
if (!midGr.get(mid_id))
return null;
gs.debug("CommonMidServerSelector.findMidForCloud: Returned MID {0}", midGr.name);
return midGr.name;
},
type: 'CommonMIDServerSelector'
};
Sys ID
d50b4e607f3112005598baf8befa9178