Name

sn_itom_pattern.CPGChangeProcessingUtil

Description

No description available

Script

var CPGChangeProcessingUtil = Class.create();
CPGChangeProcessingUtil.prototype = {
  initialize: function() {
  },

  updateResourceGroupNameInObjectID: function(objectId) {
  	var value;
  	var parts = /\/subscriptions\/.*\/resourceGroups\/(.*?)\/.*/i.exec(objectId);
  	if (parts)
  		value = objectId.replace(parts[1], parts[1].toLowerCase());

  	return value;
  },
  
  getObjectIDOfResourceGroup: function(objectId) {
  	var value;

  	var parts = /(\/subscriptions\/.*\/resourceGroups\/(.*?))(\/.*?)/.exec(objectId);
  	if (parts)
  		value = parts[1];

  	return value.toLowerCase();
  },

  buildUniqueObjectsPayloadForIRE: function(payload, processedIndexes, changePayloadGR, startIndex) {
  	var payloadInfoId = changePayloadGR.getUniqueValue();
  	var uniqueObjectArray = [];
  	var cloudModelObjects = [];

  	for (i in payload) {
  		if (processedIndexes.indexOf(i) == -1) {
  			//IRE can process only unique payloads. we are filtering payload by resource group because all the resources has relationship with resource group.
  			//if we don't filter paylaods by resource group, we get error because we refer object_id of resource group in all resources.
  			var targetResourceType = payload[i].resourceType;
  			var object_id = payload[i].targetResourceId.toLowerCase();

  			if (uniqueObjectArray.indexOf(object_id) == -1) {
  				processedIndexes.push(i);

  				uniqueObjectArray.push(object_id);
  				var objectDetailsList = payload[i].targetResourceId.split('/'); //split the object_id

  				var responseProcessor = new sn_cmp.ResponseProcessor(objectDetailsList[2], payload[i].location, 'Azure Resource Changes');
  				//build IRE bulk payload and process
  				var cloudModelObject = responseProcessor.processResponseObject(payload[i], targetResourceType, null);
  				cloudModelObjects.push(cloudModelObject);
  			}
  		}
  	}

  	gs.debug(gs.getMessage('Azure Change Processing - Sending {0} resource changes for IRE to bulk process the unique payloads', cloudModelObjects.length));

  	var processedPayload = new sn_cmp_api.CloudModelProcessorScript().updateCIs(new global.JSON().encode(cloudModelObjects), changePayloadGR.sys_domain);

  	//Case 1 : Errored Count - If processedPayloadValue is empty then corresponding payload has errored out at IRE end / it is duplicate
  	var processedPayloadParsed = JSON.parse(processedPayload);
  	var instanceURL = gs.getProperty('glide.servlet.uri');
  	var ireLogsUrl = instanceURL + 'syslog_list.do?sysparm_query=messageLIKEidentification_engine^sys_created_onONLast hour@javascript:gs.beginningOfLastHour()@javascript:gs.endOfLastHour()';
  	for (var l = startIndex; l < processedIndexes.length; l++) {
  		var j = processedIndexes[l] * 1;
  		var objectId = payload[j].targetResourceId;
  		var objectIdsList = payload[j].targetResourceId.split('/'); //split the object_id
  		var resource_type = objectIdsList[6] + '/' + objectIdsList[7];
  		var table_name = this.getTableByResourceType(resource_type);//can we cache it instead of querying the db.

  		objectId = this.updateResourceGroupNameInObjectID(objectId);

  		var processedPayloadKey = table_name + '~' + objectId;
  		var processedPayloadKeyExists = processedPayloadParsed.hasOwnProperty(processedPayloadKey);
  		var eventTrailErroredGR = new GlideRecord('sn_cmp_event_trail');

  		var changeDate = payload[j].changeTime;
  		var latestChangeTimeErrored = changeDate.substring(0, changeDate.indexOf(":")).replace('T', ' ') + changeDate.substring(changeDate.indexOf(":"), changeDate.length);
  		latestChangeTimeErrored = latestChangeTimeErrored.substring(0, latestChangeTimeErrored.length - 1);

  		if (!processedPayloadKeyExists) {
  			eventTrailErroredGR.setValue('change_type', payload[j].changeType);
  			eventTrailErroredGR.setValue('change_time', new GlideDateTime(latestChangeTimeErrored));
  			eventTrailErroredGR.setValue('status', 'errored');
  			eventTrailErroredGR.setValue('reason', '[code]IRE Payload has an error, to Check IRE Logs Press <a href="' + ireLogsUrl + '" target="_blank">' + '<u><b>Here</b></u>' + '</a>[/code]');
  			eventTrailErroredGR.setValue('affected_payload', JSON.stringify(payload[j]));
  			eventTrailErroredGR.setValue('payload_info', changePayloadGR.getUniqueValue());
  			eventTrailErroredGR.setValue('sys_domain', changePayloadGR.sys_domain);
  			eventTrailErroredGR.insert();
  		}

  	}

  	//populate interim telemetry information for the partial bulk payload [with unique CIs] accepted by IRE
  	var skippedCount = this.getSkippedAndErroredCountDetails(payloadInfoId, 'skipped');
  	var erroredCount = this.getSkippedAndErroredCountDetails(payloadInfoId, 'errored');

  	var processed_count = processedIndexes.length - (skippedCount + erroredCount);

  	changePayloadGR.setValue('processed_count', processed_count);
  	changePayloadGR.setValue('skipped_count', skippedCount);
  	changePayloadGR.setValue('errored_count', erroredCount);
  	changePayloadGR.update();
  },

  getSkippedAndErroredCountDetails: function(payloadInfoId, status) {
  	var eventGR = new GlideAggregate('sn_cmp_event_trail');
  	eventGR.addQuery('payload_info', payloadInfoId);
  	eventGR.addQuery('status', status);
  	eventGR.addAggregate('COUNT');
  	eventGR.query();

  	if (eventGR.next())
  		return eventGR.getAggregate('COUNT');

  	return 0;
  },

  getTableByResourceType: function(resourceType) {
  	var gr = new GlideRecord('sn_capi_resource_type');
  	gr.addQuery('name', resourceType);
  	gr.query();

  	if (gr.next() && gr.isValidField(('ci_class')))
  		return '' + gr.ci_class;

  	return '';
  },

  isCMObjectEmpty: function(cmObject) {
  	return (cmObject && Object.keys(cmObject).length === 0);
  },

  calculateDynamicFrequency: function(credential, operationName, runPeriod, currentTimestamp) {
  	var maxFrequency = gs.getProperty("sn_cmp.azure.change_enquiry.max_frequency_in_hours");

  	//Get the last successful order [multiple orders created for a schedule job based on the credential]
  	//Check when the last order is created based on which decide the frequency for next order.
  	//In case of throttling[429] in Azure, CAPI might take long time to receive the response. We have to wait until the response is received else we get out of order events.
  	var orderGR = this.getOrderRecord(credential, operationName, 7); //status is completed.

  	var lastSuccessfulOrder = null;

  	//first time schedule trigger on a fresh instance. No order record.
  	var dateTimeList = runPeriod.split(' ');

  	var dynamicTimestampToAddInSeconds = 0;
  	var setMaxFrequency = false;
  	if (orderGR) {
  		lastSuccessfulOrder = orderGR.sys_created_on;

  		//fetch last successful order in seconds
  		var lastSuccessfulOrderTimestamp = GlideDateTime.subtract(new GlideDateTime(lastSuccessfulOrder), currentTimestamp);
  		var epochTime = lastSuccessfulOrderTimestamp.getNumericValue();
  		var lastSuccessfulOrderInSeconds = epochTime / 1000; //convert to seconds

  		if (lastSuccessfulOrderInSeconds >= (maxFrequency * 60 * 60)) //greater than 4 hours.
  			setMaxFrequency = true;
  		else
  			dynamicTimestampToAddInSeconds = lastSuccessfulOrderInSeconds+1; //adding 1 seconds buffer so that we will not miss any changes when the frequency is reduced.
  	} else
  		setMaxFrequency = true;

  	var orderFormFrequency = Math.ceil(dynamicTimestampToAddInSeconds) + 'seconds';
  	if (setMaxFrequency) //time in hours from property [this will happen during the 1st time / when mid is down for long time and just awake]
  		orderFormFrequency = maxFrequency + 'hours';
  	else if (dynamicTimestampToAddInSeconds >= 60) //convert to minutes
  		orderFormFrequency = Math.ceil(dynamicTimestampToAddInSeconds / 60) + 'minutes';

  	return orderFormFrequency;
  },

  getOrderRecord: function(credential, operationName, status) {
  	var credentialString = '"Credential":"' + credential + '"';
  	var orderGR = new GlideRecord('sn_cmp_order');
  	orderGR.addQuery('entity_type', '2');
  	orderGR.addQuery('operation_name', operationName);
  	orderGR.addQuery('status', status); //status is completed.
  	orderGR.addQuery('order_form_data', 'CONTAINS', credentialString);
  	orderGR.orderByDesc('sys_created_on');
  	orderGR.setLimit(1);
  	orderGR.query();

  	if (orderGR.next())
  		return orderGR;

  	return null;
  },

  type: 'CPGChangeProcessingUtil'
};

Sys ID

ee2f9f17877ce150fe6d65783cbb35f9

Offical Documentation

Official Docs: