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

Offical Documentation

Official Docs: