Name

global.DiscoveryIpAddressHandler

Description

Provides functionality to prevent IP flip flop on hardware CIs

Script

var DiscoveryIpAddressHandler;

(function() {
  /**********************************************
  			    Local Variables
  ***********************************************/
  var mainCiIpList = [];
  var inputPayload = null;

  /**********************************************
  				  Public API
  ***********************************************/
  DiscoveryIpAddressHandler = {
  	getPayloadWithoutIpAddressForHardwareCis: getPayloadWithoutIpAddressForHardwareCis,
  	findOrUpdateIpAddress: findOrUpdateIpAddress,

  	// exposed for testing
  	getCiPayloadsWithIpAddress: getCiPayloadsWithIpAddress
  };
  
  function getPayloadWithoutIpAddressForHardwareCis(payload) {
  	payload = JSON.parse(payload);
  	inputPayload = payload;

  	var ciTypesExtendingHardware = GlideDBObjectManager.get().getAllExtensions('cmdb_ci_hardware');
  	// iterate over hardware CIs and remove ip_address attribute on the CI before payload is processed by IRE
  	for (var index = 0; index < payload.items.length; index++) {
  		var item = payload.items[index];
  		if (ciTypesExtendingHardware.contains(item.values.sys_class_name)) {
  			// extract ip_address attribute and remove ip_address from the CI input for all hardware CIs and put the value in memory
  			// keeping track of index for usage during ip_address reconciliation
  			mainCiIpList[index] = item.values.ip_address;
  			
  			// deleting an attribute on an object could be less efficient than setting the attribute to undefined
  			// when using JSON.stringify(), Rhino will ignore all properties set to undefined in the result string.
  			item.values.ip_address = undefined;
  		}
  	}

  	return JSON.stringify(payload);
  }

  function findOrUpdateIpAddress(ireOutput) {
  	var ciPayloadsWithIpAddress = getCiPayloadsWithIpAddress(ireOutput);
  	if (ciPayloadsWithIpAddress.items.length < 1)
  		return;
  	
  	var discoverySource = gs.getProperty("glide.discovery.source_name", "ServiceNow");
  	SNC.IdentificationEngineScriptableApi.createOrUpdateCI(discoverySource, JSON.stringify(ciPayloadsWithIpAddress));
  }

  function getCiPayloadsWithIpAddress(ireOutput) {
  	var parsedOutputPayload = JSON.parse(ireOutput);

  	var ipList = [];
  	for (index = 0; index < inputPayload.items.length; index++) {
  		item = inputPayload.items[index];
  		if ('cmdb_ci_ip_address' == item.values.sys_class_name) {
  			ipList.push(item.values.ip_address);
  		}
  	}

  	// extract main CIs from the IRE output payload for ip_address reconciliation
  	var ciPayloadsWithIpAddress = {
  		items: []
  	};

  	mainCiIpList.forEach(function(discoveredIpAddress, ciIndex) {
  		if (JSUtil.nil(discoveredIpAddress))
  			return;
  		
  		var operationType = parsedOutputPayload.items[ciIndex].operation;
  		if (operationType == 'UPDATE' || operationType == 'NO_CHANGE') {
  			// try to fetch the CI record with ip_address value not one of IPs discovered.
  			// if a record exists, it means the ip_address found on ciGr was not discovered and needs to be updated.
  			// using glide aggregate here as it offers better DB performance compared to glide record
  			var ciSysId = parsedOutputPayload.items[ciIndex].sysId;
  			var ciGr = new GlideAggregate(parsedOutputPayload.items[ciIndex].className);
  			ciGr.addQuery('sys_id', ciSysId);
  			ciGr.addQuery('ip_address', 'NOT IN', ipList);
  			ciGr.addAggregate('COUNT', 'ip_address');
  			ciGr.query();

  			if (!ciGr.hasNext())
  				return;

  			// if we are here, the ip address on the CI couldn't be discovered. 
  			// run CI through IRE with ip_address attribute set to discoveredIpAddress
  			var ciPayload = inputPayload.items[ciIndex];
  			ciPayload.values.ip_address = discoveredIpAddress;

  			ciPayloadsWithIpAddress.items.push(ciPayload);
  		}
  	});

  	return ciPayloadsWithIpAddress;
  }
})();

Sys ID

472639fc770e6110996857792c5a9986

Offical Documentation

Official Docs: