Name

global.PatternPayloadUtil

Description

This script include contains logic working on patterns input payloads

Script

var PatternPayloadUtil;

(function() {
  /**********************************************
  				  Constants
  ***********************************************/
  var SOURCE_NATIVE_KEY = 'source_native_key',
  	LOG_PREFIX = '[PatternPayloadUtil]';

  /**********************************************
  			    Local Variables
  ***********************************************/
  var cloudResourceFilter = [
  		{
  			name: 'Filter Service Accounts',
  			classType: 'cmdb_ci_cloud_service_account',
  			includeExtendedTables: false,
  			execute: function(payloadToFilter, availableData) {
  				var valuesToMatchWith = new CloudResourceDiscoveryUtil().fetchSelectedAccountsBySchedule(availableData.schedule),
  					attributes = ['account_id', 'object_id'];
  				return PatternPayloadUtil.defaultFilters.findAnyAttributeExactMatch(payloadToFilter, attributes, valuesToMatchWith);
  			}
  		},
  		{
  			name: 'Filter LDCs',
  			classType: 'cmdb_ci_logical_datacenter',
  			includeExtendedTables: true,
  			execute: function(payloadToFilter, availableData) {
  				var valuesToMatchWith = new CloudResourceDiscoveryUtil().fetchSelectedRegionsBySchedule(availableData.schedule),
  					attributes = ['name', 'region'];
  				return PatternPayloadUtil.defaultFilters.findAnyAttributeExactMatch(payloadToFilter, attributes, valuesToMatchWith);
  			}
  		},
  		{
  			name: 'Filter Availability Zones',
  			classType: 'cmdb_ci_availability_zone',
  			includeExtendedTables: false,
  			execute: function(payloadToFilter, availableData) {
  				var valuesToMatchWith = new CloudResourceDiscoveryUtil().fetchSelectedRegionsBySchedule(availableData.schedule),
  					attributes = ['name'];
  				return PatternPayloadUtil.defaultFilters.findAnyAttributeContainsMatch(payloadToFilter, attributes, valuesToMatchWith);
  			}
  		}
  	];
  var partialItemStatus = {
  	pending: 'Pending',
  	resolved: 'Resolved',
  	failed: 'Failed'
  };

  /**********************************************
  				  Public API
  ***********************************************/

  PatternPayloadUtil = {
  	chooseDiscoveryTypeFilter: _chooseDiscoveryTypeFilter,
  	filterPayload: _filterPayload,
  	extractAttributesFromPayload: _extractAttributesFromPayload,
  	extractPartialPayloadIds: _extractPartialPayloadIds,
  	findActivePartialInserts: _findActivePartialInserts,
  	valuesJsonObjectAsPayloadItem: _valuesJsonObjectAsPayloadItem,
  	defaultFilters: {
  		findAnyAttributeExactMatch: _findAnyAttributeExactMatch,
  		findAnyAttributeContainsMatch: _findAnyAttributeContainsMatch
  	}
  };

  function _chooseDiscoveryTypeFilter(discoveryType) {
  	switch (discoveryType) {
  		case DiscoveryPatternOrchestratorFlowLauncher.discoveryType.cloudResources:
  			return cloudResourceFilter;
  		case DiscoveryPatternOrchestratorFlowLauncher.discoveryType.serverless:
  			return [];
  		default:
  			return [];
  	}
  }

  function _filterPayload(filters, itemsToFilter, filterContext) {
  	var filteredPayload = itemsToFilter;

  	filters.forEach(function(filter) {
  		filteredPayload = filter.execute(filteredPayload, filterContext);
  	});

  	return filteredPayload;
  }

  function _extractAttributesFromPayload(payloadItems, attributesMap) {
  	var payloadArray = [],
  		classArray = [],
  		extractedPayload = {};

  	if (!attributesMap)
  		return JSON.parse(JSON.stringify(payloadItems));

  	payloadItems.forEach(function(item) {
  		var attributes, name, values, sourceInfo;

  		var itemResult = {};

  		for (var key in item) {
  			switch(key) {
  				case 'className':
  					name = item[key];
  					itemResult[key] = name;
  					break;
  				case 'values':
  					values = item[key];
  					itemResult[key] = {};
  					break;
  				case 'sys_object_source_info':
  					sourceInfo = item[key];
  					break;
  			}
  		}

  		if (attributesMap.hasOwnProperty(name))
  			attributes = attributesMap[name];

  		if (attributes) {
  			for (var element in values) {
  				if (attributes.indexOf(element) != -1)
  					itemResult['values'][element] = values[element];
  			}

  			if (sourceInfo &&
  				sourceInfo.hasOwnProperty(SOURCE_NATIVE_KEY) &&
  				(attributes.indexOf(SOURCE_NATIVE_KEY) > -1))
  				itemResult['values'][SOURCE_NATIVE_KEY] = sourceInfo[SOURCE_NATIVE_KEY];

  			var payloadObj = {};
  			payloadObj[name] = itemResult;
  			payloadArray.push(payloadObj);

  			if (classArray.indexOf(name) == -1)
  				classArray.push(name);
  		}
  	});

  	classArray.forEach(function(ciClass) {
  		var combinedPayload = [];

  		payloadArray.forEach(function(result) {
  			var key = Object.keys(result);

  			if (key == ciClass)
  				combinedPayload.push(result[key]);
  		});
  		extractedPayload[ciClass] = combinedPayload;
  	});

  	return extractedPayload;
  }

  function _extractPartialPayloadIds(outputPayload) {
  	if (outputPayload == null)
  		return [];

  	var payloadObject = null;
  	
  	try {
  		payloadObject = JSON.parse(outputPayload);

  		if (payloadObject == null)
  			return [];
  	} catch(e) {
  		var logger = new sn_automation.AutomationAPI().getNodeLogger();
  		logger.warn("Invalid JSON detected while extracting partial payload ids " + outputPayload);
  		
  		return [];
  	}
  	
  	var partialIdSet = {};
  	
  	if (payloadObject.items != null)
  		payloadObject.items.forEach(_extractPartialIdFromElement);
  	
  	if (payloadObject.relations != null)
  		payloadObject.relations.forEach(_extractPartialIdFromElement);

  	return Object.keys(partialIdSet);

  	function _extractPartialIdFromElement(element) {
  		if (element.partialSysId)
  			partialIdSet[element.partialSysId] = true;
  		
  		if (element.partialSysIds) {
  			for (var i = 0; i < element.partialSysIds.length; i++) 
  				partialIdSet[element.partialSysIds[i]] = true;			
  		}
  	}
  }

  function _findActivePartialInserts(statusId) {
  	var partialInserts = new GlideRecord('sn_discovery_pattern_orchestrator_partial_inserts');
  	partialInserts.addQuery('status_id', statusId);
  	partialInserts.query();

  	if (!partialInserts.hasNext())
  		return;
  	
  	var partialPayloadQuery = new GlideRecord('cmdb_ire_partial_payloads');

  	var unresolvedPartialPayloads = {};
  		
  	while (partialInserts.next()) {
  		partialPayloadQuery.get('sys_id', partialInserts.partial_payload_id + '');
  		if (partialPayloadQuery.active) {
  			var pattern = partialInserts.getDisplayValue('pattern_id');
  			if (unresolvedPartialPayloads[pattern] == null)
  				unresolvedPartialPayloads[pattern] = [];

  			unresolvedPartialPayloads[pattern].push(partialInserts.getValue('partial_payload_id'));

  			partialInserts.setValue('state', partialItemStatus.failed);
  			partialInserts.update();

  			continue;
  		}

  		partialInserts.setValue('state', partialItemStatus.resolved);
  		partialInserts.update();
  	}
  	
  	_printPartialInsertResults(unresolvedPartialPayloads, statusId);
  }

  function _valuesJsonObjectAsPayloadItem(values, asClass) {
  	return {
  		className: asClass,
  		values: values
  	};
  }
  /**********************************************
  			Private Helper Functions
  ***********************************************/

  function _getFilteredPayloadForIncopmleteInputs(payloadToFilter, attributesToFind, valuesToMatch, logger, logPrefix) {

  	if (!payloadToFilter || (payloadToFilter.length == 0)) {
  		logger.warn(LOG_PREFIX + logPrefix  + ' No payload to filter');
  		return [];
  	}

  	if (!attributesToFind || (attributesToFind.length == 0)) {
  		logger.warn(LOG_PREFIX + logPrefix + ' No filering attributes provided. No filtering performed');
  		return payloadToFilter;
  	}

  	if (!valuesToMatch || (valuesToMatch.length == 0)) {
  		logger.warn(LOG_PREFIX + logPrefix + ' No filering values provided. No filtering performed');
  		return payloadToFilter;
  	}
  	
  	return null;
  }

  // TODO: Remove common logic from both matching strategies
  function _findAnyAttributeExactMatch(payloadToFilter, attributesToFind, valuesToMatch) {
  	var logger = new sn_automation.AutomationAPI().getNodeLogger(),
  		filterIdentifierLogPrefix = '[' + gs.generateGUID() + ']';

  	logger.debug(LOG_PREFIX + filterIdentifierLogPrefix + ' Preparing running filter using exact match comparison\n'
  				+ 'Payload: ' + JSON.stringify(payloadToFilter) + '\n'
  				+ 'Attributes to find: ' + JSON.stringify(attributesToFind) + '\n'
  				+ 'Values to match: ' + JSON.stringify(valuesToMatch));

  	var filteredPayload = _getFilteredPayloadForIncopmleteInputs(payloadToFilter, attributesToFind, valuesToMatch, logger, filterIdentifierLogPrefix);

  	if (filteredPayload != null)
  		return filteredPayload;

  	logger.info(LOG_PREFIX + filterIdentifierLogPrefix + ' Filtering input payload...');

  	filteredPayload = payloadToFilter.filter(function(item) {
  		logger.debug(LOG_PREFIX + filterIdentifierLogPrefix + ' Inspecting item: ' + JSON.stringify(item));
  		var didFindAttribute = false;

  		for (var index in attributesToFind) {
  			var attribute = attributesToFind[index];
  			logger.debug(LOG_PREFIX + filterIdentifierLogPrefix + ' Looking for attribute "' + attribute + '" in item');

  			if (item.values[attribute]) {
  				var valueInPayload = item.values[attribute];
  				logger.debug(LOG_PREFIX + filterIdentifierLogPrefix + ' Attribute found with value "' + valueInPayload + '"');
  				didFindAttribute = (valuesToMatch.indexOf(valueInPayload) != -1);
  				var didFindAttributeLog = didFindAttribute ? 'found' : 'not found';

  				logger.debug(LOG_PREFIX + filterIdentifierLogPrefix + ' "' + valueInPayload + '" ' + didFindAttributeLog + ' in ' + JSON.stringify(valuesToMatch));

  				if (didFindAttribute)
  					break;
  			}
  		}
  		return didFindAttribute;
  	});

  	logger.info(LOG_PREFIX + filterIdentifierLogPrefix + ' Filtering finished...');
  	logger.debug(LOG_PREFIX + filterIdentifierLogPrefix + ' Filtered payload:\n' + JSON.stringify(filteredPayload));

  	return filteredPayload;
  }

  // TODO: Remove common logic from both matching strategies
  function _findAnyAttributeContainsMatch(payloadToFilter, attributesToFind, valuesToMatch) {
  	var logger = new sn_automation.AutomationAPI().getNodeLogger(),
  		filterIdentifierLogPrefix = '[' + gs.generateGUID() + ']';

  	logger.debug(LOG_PREFIX + filterIdentifierLogPrefix + ' Preparing running filter using containment match comparison\n'
  				+ 'Payload: ' + JSON.stringify(payloadToFilter) + '\n'
  				+ 'Attributes to find: ' + JSON.stringify(attributesToFind) + '\n'
  				+ 'Values to match: ' + JSON.stringify(valuesToMatch));

  	var filteredPayload = _getFilteredPayloadForIncopmleteInputs(payloadToFilter, attributesToFind, valuesToMatch, logger, filterIdentifierLogPrefix);

  	if (filteredPayload != null)
  		return filteredPayload;

  	logger.info(LOG_PREFIX + filterIdentifierLogPrefix + ' Filtering input payload...');

  	filteredPayload = payloadToFilter.filter(function(item) {
  		logger.debug(LOG_PREFIX + filterIdentifierLogPrefix + ' Inspecting item: ' + JSON.stringify(item));
  		var hasMatchesInPayload = false;

  		for (var index in attributesToFind) {
  			var attribute = attributesToFind[index];
  			logger.debug(LOG_PREFIX + filterIdentifierLogPrefix + ' Looking for attribute "' + attribute + '" in item');

  			if (item.values[attribute]) {
  				var valueInPayload = item.values[attribute];
  				logger.debug(LOG_PREFIX + filterIdentifierLogPrefix + ' Attribute found with value "' + valueInPayload + '"');

  				hasMatchesInPayload = valuesToMatch.some(function(element) {
  					var didFindPartialMatch = (valueInPayload.toLowerCase().indexOf(element.toLowerCase()) != -1),
  					didFindPartialMatchLog = didFindPartialMatch ? 'contains' : 'doesn\'t contain';

  					logger.debug(LOG_PREFIX + filterIdentifierLogPrefix + ' "' + valueInPayload + '" ' + didFindPartialMatchLog + ' "' + element + '"');

  					return didFindPartialMatch;
  				});
  				
  				if (hasMatchesInPayload)
  					break;
  			}
  		}
  		return hasMatchesInPayload;
  	});

  	logger.info(LOG_PREFIX + filterIdentifierLogPrefix + ' Filtering finished...');
  	logger.debug(LOG_PREFIX + filterIdentifierLogPrefix + ' Filtered payload:\n' + JSON.stringify(filteredPayload));

  	return filteredPayload;
  }
  
  function _printPartialInsertResults(unresolvedPartialPayloads, statusId) {
  	var allowCodeTag = gs.getProperty('glide.ui.security.allow_codetag', true) + '' == 'true';

  	var count = 0;
  	var logResult = 'Uncompleted partial payloads persisted in Discovery flow.';

  	if (!allowCodeTag)
  		logResult = logResult + '(cmdb_ire_partial_payloads)\n';
  	else
  		logResult = logResult + '<br/>';

  	for (var patternKey in unresolvedPartialPayloads) {
  		if (unresolvedPartialPayloads[patternKey].length == 0)
  			continue;

  		logResult = logResult + patternKey + ' - ';

  		if (allowCodeTag && unresolvedPartialPayloads[patternKey].length < 50) {
  			logResult = logResult +
  				'<a href="cmdb_ire_partial_payloads_list.do?sysparm_query=sys_idIN' +
  				unresolvedPartialPayloads[patternKey].join() +
  				'">Records</a><br/>';
  		} else {
  			logResult = logResult + unresolvedPartialPayloads[patternKey].join() + '\n';
  		}

  		count += unresolvedPartialPayloads[patternKey].length;
  	}

  	if (count == 0)
  		return;

  	if (allowCodeTag)
  		logResult = "[code]" + logResult + "[/code]";

  	var logger = new DiscoveryLogger(statusId);
  	logger.warn(logResult);
  }
})();

Sys ID

c9f7ed010ff140106dc4fe39b4767ec8

Offical Documentation

Official Docs: