Name

global.EvtMgmtCalculateImpactForGroups

Description

Calculating the impact for groups

Script

gs.include('SlowStepJSManager');

var EvtMgmtCalculateImpactForGroups = Class.create();
EvtMgmtCalculateImpactForGroups.prototype = {
  initialize: function() {
  	this.maxQueueIterations = gs.getProperty("evt_mgmt.EvtMgmtCalculateImpactForGroups.max_queue_iterations",1000000);
  	this.debug=gs.getProperty("evt_mgmt.EvtMgmtCalculateImpactForGroups.debug",'false');
  	this.debugQueue=gs.getProperty("evt_mgmt.EvtMgmtCalculateImpactForGroups.queue.debug",'false');
  	this.getBSSeveriryFromServiceAuto=gs.getProperty("evt_mgmt.EvtMgmtCalculateImpactForGroups.bs_from_auto",'true');
  	this.supportAlertsImpactDirectlyOnGroups=gs.getProperty("evt_mgmt.support_alerts_impact_directly_on_service_groups",'false');
  	this.insertAllUnchanged=gs.getProperty("evt_mgmt.insert_also_unchanged_impact_records",'false');
  	this.filterOutAll=gs.getProperty("evt_mgmt.EvtMgmtCalculateImpactForGroups.filterOutAll",'true');
  	this.bsToGroupsMap={}; //bs -> groups
  	this.groupsToSeverityMap={};//groupId -> severity
  	this.groupsToParent={}; //group -> parent
  	this.groupToChildren={}; // group -> children
  	this.groupsImpactStatusMap={};//map with the original groups severity
  	this.queue=[];
  	this.queueMap={};
  	this.impactStatusRecordToInsert=[];
  	this.fImpactManager= new SNC.ImpactManager();
  	this.fSlowStepJSManager = new SlowStepJSManager();
  	this.evtMgmtCommons  = new EvtMgmtCommons();
  	this.maxCisForDotWalkingWithCMDB=gs.getProperty("evt_mgmt.max_cis_for_dot_walking_with_cmdb",36000000);
  	this.canUseDotWalkingWithCMDB=this.getUseDotWalkingWithCMDB();

  	this.INFO_SEVERITY=5;
  	this.CLEAR_SEVERITY=0;
  	this.LAST_SERVICE_GROUPS_IMPACT_TIME_CALC="last_impact_time_calc_job_service_groups";
  	this.LAST_SERVICE_GROUPS_STATUS_UPDATE_TIME="last_impact_update_time_status_service_groups";
  	this.ALL_GROUP_SYS_ID = "0e7a06157f10310016181ccebefa91ce";

  	
  },

  type: 'EvtMgmtCalculateImpactForGroups',
  
  calculateImpactForGroups: function(){
  	if (this.evtMgmtCommons.isImpactCalculationEnabled())
          this.runCalculation();
  },
  
  //This function is used for tests purposes, even when impact flag is disabled. 
  runCalculation: function() {
  	var startTime=new Date();
  	this.fSlowStepJSManager.setTopic("EvtMgmtCalculateImpactForGroups");
  	gs.debug('Impact service for groups started the calculation, time is: '+startTime);

  	var lastGroupJobRunGR = this.evtMgmtCommons.getHashGr(this.LAST_SERVICE_GROUPS_IMPACT_TIME_CALC);
  	var lastGroupStr = "";
  	if (lastGroupJobRunGR.next()) {
  		lastGroupStr = lastGroupJobRunGR.hash;
  	}


  	//Get Min impact time, to use for the vt_start as well as timestamp
  	var minLastImpactTime = this.fImpactManager.getMinLastImpactJobRun();

  	//Enter the if didn't found the time yet (first job run) or something changed
  	if ((!lastGroupStr) || (lastGroupStr !=minLastImpactTime)) {
          if (this.filterOutAll == 'false' || !this.noServiceGroupsDefined()) {
              //setting the map of services->group and initialize the severity of the groups from the impact status records of the BS's
              this.setServicesToGroupsMap();
              //setting the initial severity of the groups
              this.setInitialGroupsSeverity(minLastImpactTime);
              //getting the impact status records for the BS's and setting the group-> severity map (optional: calculation dierectly on the group)
              if (this.getBSSeveriryFromServiceAuto == 'true') {
                  this.debugPrint("Getting bs severities from service auto table");
                  this.setSeveritiesForBSGroups();
              } else {
                  this.debugPrint("Getting bs severities from impact status table");
                  var servicesImpactStatusRecords = this.getServicesImpactStatusRecords(minLastImpactTime);
                  this.setSeveritiesToGroups(servicesImpactStatusRecords);
              }
              //setting two maps: group->parent and parent -> groups
              this.setGroupsToParentAndParentsToGroupsMaps();
              //adding the groups that are not parents (leaf) to the queue (to be calculated)
              this.addFirstLevelOfParentsInGroupsToQueue();
              //calculating all the severity of the groups by adding the parents iteratively to the queue
              this.updateSeveritiesByQueue();
              //creating objects as native objects and save it on the DB
              this.saveChangedGroupsSeverityToDB(minLastImpactTime);
          } else {
              gs.debug('Impact service for groups did not calculated since there are no service groups rather then \'All\'');
          }
          //Update hash times	of last run and last change
  		this.updateHashTimeStamp(minLastImpactTime);

  	} else {
  		gs.debug('Impact service for groups did not calculated since no impact job ran from last job run');
  	}

  	this.slowStepsManager.report();
  	var endTime=new Date();
  	var duration = (endTime.getTime()) - startTime.getTime();
  	var perfJson = {};
  	perfJson.impactStatusRecordToInsertSize = this.impactStatusRecordToInsert.length;
  	perfJson.lastGroupJobRunHash = lastGroupStr + "";
  	perfJson.CurrentJobRunHash = minLastImpactTime + "";

  	this.evtMgmtCommons.writeToPerfTable("evtMgmtCalculateImpactForGroups", this.impactStatusRecordToInsert.length, duration, perfJson);
  	
  	this.evtMgmtCommons.addDebugLogNoPrefix('Impact service for groups finished to calculate and inserted ' + this.impactStatusRecordToInsert.length+' new records, duration is ' + duration);
  
  },
  
  debugPrint: function(msg) {
  	if(this.debug=='true'){
  		gs.print(msg);
  	}
  },
  
  debugQueuePrint: function(msg) {
  	if(this.debugQueue=='true'){
  		gs.print(msg);
  	}
  },
  
  updateHashTimeStamp: function(minLastImpactTime) {
  	
  	var hashes = [""];
  	
  	this.evtMgmtCommons.setHashGr(this.LAST_SERVICE_GROUPS_IMPACT_TIME_CALC, minLastImpactTime);

  	if (this.impactStatusRecordToInsert.length >0) {
  		this.evtMgmtCommons.setHashGr(this.LAST_SERVICE_GROUPS_STATUS_UPDATE_TIME, minLastImpactTime);
  	}		
  },
  
  setInitialGroupsSeverity:function(minLastImpactTime){
  	this.fSlowStepJSManager.startStep("Setting the initial severity of the groups");
  	var groupsGR=this.fImpactManager.getAllServiceGroupsImpactStatusRecords(minLastImpactTime);
  	while(groupsGR.next()){
  		this.groupsImpactStatusMap[groupsGR.element_id]=groupsGR.severity+'';
  	}
  	

  },
  
  setServicesToGroupsMap: function() {
  	this.fSlowStepJSManager.startStep("Setting bsToGroupsMap");
      var grServiceRelation = new GlideRecord('sa_service_group_member');
  	if (this.canUseDotWalkingWithCMDB) {
  		grServiceRelation.addQuery('service.operational_status', '1');
  		grServiceRelation.addQuery('service.severity', '!=', '5'); //exclude services with OK severity
  	}
  	//exclude services that are in the All group - their impact is calculated separately in BusinessServiceTreeBuilder.PresentationModeAssurance.calculateRootSeverity
  	if (this.filterOutAll == 'true') {
  		grServiceRelation.addQuery('service_group', '!=', this.ALL_GROUP_SYS_ID);
  	}
      grServiceRelation.query();
      while(grServiceRelation.next()) {
          var bsSysId = grServiceRelation.service;
          var groupId = grServiceRelation.service_group;
  		
          if (!(this.bsToGroupsMap[bsSysId])) {
              this.bsToGroupsMap[bsSysId] = {};
          }
          (this.bsToGroupsMap[bsSysId])[groupId] = {};
  		
  		if (this.canUseDotWalkingWithCMDB) {
  			var severity = grServiceRelation.service.severity;
  			this.setSeverityToGroup(groupId, severity);
  		}
      }
  	if (this.debug=='true') {
          gs.print("There are " + Object.keys(this.bsToGroupsMap).length + " bs");
          for (var bs in this.bsToGroupsMap) {
              gs.print("bs " + bs + " has " + Object.keys(this.bsToGroupsMap[bs]).length  + " groups.");
          }
      }
  },
  
  //add the severity for each group that has this BS in it
  setSeverityToGroups: function(groupsOfService,serviceSeverity) {
      if (groupsOfService) {
          for (var group in groupsOfService) {
  			this.setSeverityToGroup(group,serviceSeverity);
  		}
      }
  },
  
  //add the severity to a single group
  setSeverityToGroup: function(group,severity){
  	this.debugPrint("adding severity " + severity + " to group " +group);
  			var currentGroupStatus = this.groupsToSeverityMap[group];
  			if (!currentGroupStatus) {
  				this.groupsToSeverityMap[group] = this.INFO_SEVERITY;
  			}
  			
  			//lower number indicates on more severe severity (except 0 which is Clear severity)
  			if (severity < this.groupsToSeverityMap[group] && severity!=this.CLEAR_SEVERITY){
  				this.groupsToSeverityMap[group]=severity+'';
  			}
  },
  
  getServicesImpactStatusRecords: function(minLastImpactTime) {
  	this.fSlowStepJSManager.startStep("Getting all the impact status records for the operational BS's");
  	return this.fImpactManager.getAllOperationalServicesImpactStatusRecords(minLastImpactTime);
  },
  
  setSeveritiesToGroups: function(impactStatusRecords){
  	//setting the severities from the BSs
  	while(impactStatusRecords.next()) {
  		if (impactStatusRecords.element_id == impactStatusRecords.business_service) {				
  			this.debugPrint("severity of bs " + impactStatusRecords.business_service +" element id "+ impactStatusRecords.element_id+" is " + impactStatusRecords.severity);
  			this.setSeverityToGroups(this.bsToGroupsMap[impactStatusRecords.element_id],  impactStatusRecords.severity);        
  		}            
      }
  	this.debugPrintAllGroupsStatuses();
  	this.calcAlertOnServiceGroup();
  	
  },
  
  
  setSeveritiesForBSGroups: function(){
  	if (!this.canUseDotWalkingWithCMDB){
  		//setting the severities from the BSs	
  		var gr = new GlideRecord("cmdb_ci_service_auto");	
  		gr.addQuery("operational_status", "1");	
  		gr.query();	
  		while (gr.next()) {	
  			this.setSeverityToGroups(this.bsToGroupsMap[gr.sys_id],  gr.severity);	
  		}
  	}
  	this.debugPrintAllGroupsStatuses();
  	this.calcAlertOnServiceGroup();
  	
  },
  
  
  calcAlertOnServiceGroup: function() {
  	if(this.supportAlertsImpactDirectlyOnGroups=='true'){
  		this.fSlowStepJSManager.startStep("Fetching the history alerts for the groups");
  		//setting the severities from the alert history directly on the groups
  		var relatedHistoryAlerts=this.fImpactManager.getLastAlertHistoryForGroups();
  		while(relatedHistoryAlerts.next()){
  			if (relatedHistoryAlerts.state != 'Closed') {   // Don't fetch closed alert
  				this.setSeverityToGroup(relatedHistoryAlerts.cmdb_ci,  relatedHistoryAlerts.severity);     
  			}
  		}
  	}
  },
  
  debugPrintAllGroupsStatuses: function() {
      if (this.debug=='true') {
          for (var group in this.groupsToSeverityMap) {
              gs.print("group " + group + " severity is: " + this.groupsToSeverityMap[group]);
          }
      }
  },
  
  saveChangedGroupsSeverityToDB:function(minLastImpactTime) {
  	this.fSlowStepJSManager.startStep("Saving the changed groups to the DB");
      for (var group in this.groupsToSeverityMap) { 
  		if(this.insertAllUnchanged=='true' || this.groupsToSeverityMap[group]!=this.groupsImpactStatusMap[group] ){
  			var groupImpactObject=this.getImpactStatusObject(group);
  			this.impactStatusRecordToInsert.push(groupImpactObject);
  		}	            
      }
  	this.fImpactManager.insertGroupImpactStatusRecords(this.impactStatusRecordToInsert, minLastImpactTime);
  },
  
  getImpactStatusObject: function(groupId) {
  	var impactStatusObject={};
  	impactStatusObject.id=groupId;
  	impactStatusObject.severity=this.groupsToSeverityMap[groupId];
      return impactStatusObject;
  },
  
  setGroupsToParentAndParentsToGroupsMaps: function() {
      var groupsGR = new GlideRecord("cmdb_ci_service_group");
      groupsGR.query();
      while(groupsGR.next()) { 
  		var parentGroup=groupsGR.parent_group + "";
  		var groupId=groupsGR.sys_id+'';
          this.groupsToParent[groupId] = parentGroup;
          var childrenArray = this.groupToChildren[parentGroup];
          if (!childrenArray) {
              childrenArray = [];
              this.groupToChildren[parentGroup] = childrenArray;
          }
          childrenArray.push(groupId);
      }
  },
  
  addFirstLevelOfParentsInGroupsToQueue: function(){
      for (var group in this.groupsToParent) {
          var groupChildren = this.groupToChildren[group];
  		//if the group doesn't have children, he's a node leaf
          if (groupChildren==undefined) {
              if (!(this.checkGroupInQueue(group))) {
                  this.pushToQueue(group);
              }
          } else {
              this.debugPrint("Group " + group + " has no parent.");
          }
      }
  },
  
  updateSeveritiesByQueue: function(){  
  	this.fSlowStepJSManager.startStep("Calculating all the impact for the groups");
      var counter =0;
      while (this.queue.length > 0 && (counter <= Number(this.maxQueueIterations))) {
          counter++;
          var group = this.popFromQueue();

  		if(!this.groupsToSeverityMap[group]){
  			this.groupsToSeverityMap[group] = this.INFO_SEVERITY;
  		}
  		
  		//iterating on the children groups and update the parent if child severity is more severe
          var children = this.groupToChildren[group];
          for (var i=0;i<children.length;i++) {
  			//lower number indicates on more severe severity (except 0 which is clear severity)
              if(this.groupsToSeverityMap[children[i]]<this.groupsToSeverityMap[group] && this.groupsToSeverityMap[children[i]]!=this.CLEAR_SEVERITY){
  				this.groupsToSeverityMap[group]=this.groupsToSeverityMap[children[i]];
  			}
          }
  		
  		var parent = this.groupsToParent[group];
  		if (parent) {
  			//if the parent wasn't fetched yet we initiate it with info severity
  			if(this.groupsToSeverityMap[parent]==undefined){
  				this.groupsToSeverityMap[parent]=this.INFO_SEVERITY;
  			}
  			this.pushToQueue(parent,group);
  		}
      }

      if (counter >= Number(this.maxQueueIterations)) {
          gs.error("EvtMgmtFixImpactForGroups: " + this.maxQueueIterations + " iterations on the queue, stopped calculating the impact for service groups");
          return;
      }
  	this.debugPrintAllGroupsStatuses();   

  },
  
  checkGroupInQueue: function(group) {
  	if (this.queueMap[group] != undefined){
  		return true;
  	}
      return false;
  },
  
  pushToQueue: function(group,childGroup){
  	this.queue.push(group);
  	this.queueMap[group]={};
  	this.debugQueuePrint("pushed parent: "+group+" of group "+childGroup+" to the queue, size of the queue is: "+this.queue.length+" ,queue is: "+this.queue);
  },
  
  popFromQueue: function(){
  	var group=this.queue.shift();
  	this.queueMap[group]=undefined;
  	this.debugQueuePrint("Poping from queue group: " + group + ", queue is now: " +this.queue);
  	return group;
  },

  noServiceGroupsDefined: function() {
      var res = true;
      var groupsGR = new GlideRecord("cmdb_ci_service_group");
      groupsGR.addQuery('sys_id', '!=', this.ALL_GROUP_SYS_ID);
      groupsGR.setLimit(1);
      groupsGR.query();
      return !groupsGR.next();
  },
  getCICount: function() {
  	var ciCountHashGr = this.evtMgmtCommons.getHashGr("cis_count");
  	var ciCountHash = 0;
  	if (ciCountHashGr.next()) {
  		ciCountHash = parseInt(ciCountHashGr.getValue('hash', 10));
  	}
  	return ciCountHash;
  },
  
  getUseDotWalkingWithCMDB: function() {
  	var res = false;
  	
  	var count = 0;
  	
  	var property = gs.getProperty("evt_mgmt.EvtMgmtCalculateImpactForGroups.canUseDotWalkingWithCMDB",'true') === 'true';
  	
  	if ((property != false) && (this.maxCisForDotWalkingWithCMDB != -1)) {
  		count = this.getCICount();
  		
  		if ((count != 0) && (count < this.maxCisForDotWalkingWithCMDB)) {
  			res = true;
  		}
  	}

  	this.evtMgmtCommons.addDebugLogNoPrefix('getUseDotWalkingWithCMDB = ' + res + ',  evt_mgmt.EvtMgmtCalculateImpactForGroups.canUseDotWalkingWithCMDB = ' + property + ', cis_count hash is ' + count + ', maxCisForDotWalkingWithCMDB = ' + this.maxCisForDotWalkingWithCMDB);
  	
  	return res;
  }

  
};

Sys ID

a057912867003300220d007d2685ef07

Offical Documentation

Official Docs: