Name
sn_itom_pattern.NutanixEventHandler
Description
Handling the events from Nutanix and invoking discovery pattern
Script
var NutanixEventHandler = Class.create();
var cloudPatternInvocation = new sn_itom_pattern.CloudPatternInvocation();
var nutanixProbeInvoker = new sn_itom_pattern.NutanixProbeInvoker();
var cloudApplicationDiscovery = new global.CloudApplicationDiscovery();
NutanixEventHandler.prototype = Object.extendsObject(sn_cmp.CloudEventHandler, {
initialize: function() {
},
processEvent : function(headersStr, bodyStr, queryParamsStr, eventId) {
var response = {};
var jsonBody = JSON.parse(bodyStr);
var ciType;
var objectID = this.getObjectID(jsonBody);
try {
ciType = this.extractCMDBCIType(jsonBody);
}
catch(e){
gs.error("Failed to get cmdb type for object ID "+objectID);
}
if(!ciType){
gs.warn("NutanixEventHandler: Not supported type "+this.getResourceType(jsonBody)+" with object ID "+objectID);
}else if(this.shouldInvokeDiscovery(jsonBody)){
gs.info("NutanixEventHandler: invoking discovery on event ID "+eventId+" with object ID "+objectID);
response = this.invokeDiscovery(jsonBody,eventId,objectID);
}else{
gs.info("NutanixEventHandler: handing in server event ID "+eventId+" with object ID "+objectID);
response.ci = this.handleAlertInServer(jsonBody,objectID,ciType);
}
response.state = "processed";
return response;
},
/*
* returns true if the alert should trigger a discovery
* @param jsonBody
*/
shouldInvokeDiscovery : function(jsonBody) {
// for now the only logic is that we need to check if its a delete event
// the shouldInvokeDiscovery is still here to support future cases of handling events in the server
return !this.isDeleteEvent(jsonBody);
},
/*
* handle the alert without running a discovery
* Alerts that will be handled here are
* - delete
* @param jsonBody - the event json body
* @param objectId - the CI object ID
*/
handleAlertInServer : function(jsonBody,objectId,cmdbCIType) {
var resCI;
if(this.isDeleteEvent(jsonBody)){
if (cmdbCIType == "cmdb_ci_nutanix_vm_instance"){
objectId = this.getClusterUUID(jsonBody) + "::" + objectId;
}
resCI = this.markCIAbsent(objectId,cmdbCIType);
gs.info("NutanixEventHandler: CI was marked as absent with object ID "+objectId);
}else{
gs.warn("NutanixEventHandler: No Action was set for CI with object ID "+objectId);
}
return resCI;
},
/*
* Mark the CI from type ciClass with object ID objectID as absent
* @param objectID - the object ID attribute
* @param ciClass - the cmdb class
* return: glide record of the CI that is marked as absent
*/
markCIAbsent : function(objectID, ciClass) {
var resultVal;
if (ciClass) {
var ciGR = new GlideRecord(ciClass);
if (ciGR.get('object_id', objectID)) {
gs.info("NutanixEventHandler: marking object "+objectID+" for absent");
new sn_cmp.CMPReconciler().markCIAbsent(ciGR);
resultVal = ciGR.getUniqueValue();
}
}else{
gs.error("NutanixEventHandler: failed to terminate CI "+objectID+", no cmdb_ci table was found");
}
return resultVal;
},
/*
* invoke the discovery based on alert
* @param jsonBody
* @param eventID - event ID
* @param objectID - ci object ID
*/
invokeDiscovery : function(jsonBody,eventID,objectID) {
var response = {};
var configObj = this.prepareConfigObj(jsonBody,eventID,objectID);
response.state = 'processing';
response.discovery_status = null;
response.error_message = "";
gs.info("NutanixEventHandler: Invoking discovery from event ID "+eventID+" on object id "+ objectID + " with pattern "+configObj.patternId);
var result = this.eventBasedDiscovery(configObj, response);
if (result){
//For sucess invocation the state | error_mesaage will be update in HorizontalDiscoveryResultHandler.finalizeCloudChangeEvent()
//Will be determine if the pattern is success or not
gs.info("NutanixEventHandler: Finished Event based discovery on object ID "+objectID);
}else {
gs.error("NutanixEventHandler: Failed Event based discovery on object ID "+objectID);
response.state = (response.state) ? response.state : 'error';
response.error_message = (response.error_message) ? response.error_message : gs.getMessage('Cannot invoke pattern discovery for: {0}', [JSON.stringify(configObj , null, 2)]);
}
response.resource_id = objectID;
response.resource_type = configObj.resource_type;
return response;
},
/*
* prepare the config type for invoking the discovery
* @param jsonBody
* @param eventID
* @param objectID
* @returns {{changeType: *|string, classType: *, accountId: *|string, inputObjectId: *, cloudId: *, patternId: *, eventId: *, eventType: string, eventData: string}}
*/
prepareConfigObj : function(jsonBody,eventID,objectID) {
var resourceType = this.getResourceType(jsonBody);
var invocationPatternId = this._getPatternId(resourceType);
var ciClassType = this._getClassTypeId(resourceType);
var actionType = this.getActionType(jsonBody);
var clusterUUID = this.getClusterUUID(jsonBody);
var context = this.extractContext(jsonBody);
//Prepare the mandatory parameters to pass to the pattern context
var configObj = {
changeType : actionType,
classType: ciClassType,
clusterUuid: clusterUUID,
inputObjectId: objectID,
objectID: objectID,
patternId: invocationPatternId,
eventId: eventID,
eventType: "Nutanix",
eventData: JSON.stringify(context)
};
return configObj;
},
getPatternType : function(patternID) {
var ciGr = new GlideRecord('sa_pattern');
ciGr.addQuery('sys_id',patternID);
ciGr.query();
if(ciGr.next()){
return ciGr.ci_type;
}
},
getPatternCIs : function(patternType, patternID) {
var ciGr = new GlideRecord('sa_ci_to_pattern');
ciGr.addQuery('pattern',patternID);
ciGr.query();
var rtrn = "\"" + patternType + "\"";
while(ciGr.next()){
rtrn += ", \"" + ciGr.ci_type + "\"";
}
return rtrn;
},
getResourceType : function(jsonBody) {
return "Nutanix " + jsonBody.entity_list[0].entity_type;
},
getActionType : function(jsonBody) {
return jsonBody.operation_type;
},
getClusterUUID : function(jsonBody) {
return jsonBody.cluster_uuid;
},
getObjectID : function(jsonBody) {
return jsonBody.entity_list[0].entity_id;
},
extractContext : function(jsonBody) {
return jsonBody.jsonPayload;
},
isDeleteEvent : function(jsonBody) {
// check if the type of the discovery is delete, otherwise run discovery
var res = false;
var action = this.getActionType(jsonBody);
if(action.toLowerCase().includes("delete")){
res = true;
}
return res;
},
extractCMDBCIType : function(jsonBody) {
var resouceType = this.getResourceType(jsonBody);
gs.info("NutanixEventHandler: extracting class type for "+resouceType);
var ciType;
if(resouceType){
try {
ciType = this._getClassTypeId(resouceType);
}catch (e){
gs.warn("Failed to get cmdb type for object ID "+this.getObjectID(jsonBody)+" and type "+this.getResourceType(jsonBody));
}
}
return ciType;
},
eventBasedDiscovery: function(configObj, response) {
if (configObj.changeType.toUpperCase().trim() === "DELETE") {
return cloudPatternInvocation.handleDelete(configObj, response);
} else {
var statusId = this.invokeQuickDiscovery(configObj, response);
response.discovery_status = statusId;
return (statusId)? true : false;
}
},
invokeQuickDiscovery: function(configObj, response) {
cloudPatternInvocation._debug("Start invokeQuickDiscovery", configObj);
var discoveryStatusId = cloudPatternInvocation.createDiscoveryStatus(configObj);
configObj.discoveryStatusId = discoveryStatusId;
if (discoveryStatusId) {
cloudPatternInvocation._debug("Start pattern invocation", {});
var result = this.discoverSpecificResourceByPattern(configObj);
cloudPatternInvocation._debug("End pattern invocation", result);
if (result){
return discoveryStatusId;
}else {
cloudPatternInvocation._printEventError(gs.getMessage('invokeQuickDiscovery did not succeed to invoke the pattern:'), configObj, response);
return null;
}
} else {
cloudPatternInvocation._printEventError(gs.getMessage('invokeQuickDiscovery did not succeed to create a discovery status:'), configObj, response);
return null;
}
return null; //We should not reach to this point!
},
discoverSpecificResourceByPattern: function(configObj) {
// Find MID based on Nutanix capability
var midSelector = new global.CloudMidSelectionApi();
var midID = midSelector.selectMid(null, "Nutanix", null, "{}");
var midGr = new GlideRecord('ecc_agent');
midGr.get(midID);
gs.debug("Selected MID: " + midGr.name);
var mid = midGr.name;
// Iterate over patterns and launch HorizontalDiscoveryProbe
var patternGr = new GlideRecord('sa_pattern');
patternGr.get(configObj.patternId);
if (!patternGr.isValid()) {
this._printEventError("discoverSpecificResourceByPattern-> No pattern found having sys_id " , configObj);
return false;
}
gs.info("Discovers specific resource by pattern - " + patternGr.name);
this.sendProbe(mid, configObj, patternGr.name) ;
return true;
},
getClusterIP: function(clusterUUID){
var ciGr = new GlideRecord('cmdb_ci_nutanix_cluster');
ciGr.addQuery('cluster_id',clusterUUID);
ciGr.query();
if(ciGr.next()){
return ciGr.ip_address;
}
},
sendProbe: function(midId, configObj, PatternName) {
gs.info("NutanixEventHandler: Invoking probe on Mid "+midId);
var jobName = "Pattern Launcher: " + PatternName;
var payload = this._createProbePayload(configObj, PatternName);
var clusterIp = this.getClusterIP(configObj.clusterUuid);
this._sendProbe(midId,payload,jobName,clusterIp,configObj);
},
_createProbePayload: function(configObj, PatternName) {
var payload = new XMLDocument2();
payload.createElement("parameters");
var patternType = this.getPatternType(configObj.patternId);
// prePatternExecutionData
nutanixProbeInvoker._addParameter(payload,'prePatternExecutionData', "{ \"fMapOfStrings\" : { \"input_object_id\" : \"" + configObj.inputObjectId + "\", \"cluster_uuid\" : \"" + configObj.clusterUuid + "\", \"cluster_ip\" : \"" + this.getClusterIP(configObj.clusterUuid) + "\"}, \"executePattern\" : true, \"empty\" : false, \"className\" : \"PrePatternExecutionDTO\" }");
nutanixProbeInvoker._addParameter(payload,'pattern_type', patternType);
nutanixProbeInvoker._addParameter(payload,'patternMetadata', "{ \"relatedTables\" : [ \"java.util.ArrayList\", [ \"cmdb_key_value\" ] ], \"ciTypes\" : [ \"java.util.ArrayList\", [ " + this.getPatternCIs(patternType, configObj.patternId) + " ] ] }");
// set pattern information
var computerSystem = "{ \"solaris\" : false, \"managementIP\" : \"No Source\", \"primaryManagementIP\" : \"No Source\", \"addressWidth\" : 0, \"hpux\" : false, \"aix\" : false, \"computerIP\" : \"No Source\", \"ciSnapshotId\" : 0 }";
nutanixProbeInvoker._addParameter(payload,'computerSystem', computerSystem);
nutanixProbeInvoker._addParameter(payload,'patternId', configObj.patternId);
nutanixProbeInvoker._addParameter(payload,'pattern', PatternName);
// set infra context params
nutanixProbeInvoker._addParameter(payload,'used_by_runbook', "true");
nutanixProbeInvoker._addParameter(payload,'glide.xmlhelper.trim.enable', "true");
nutanixProbeInvoker._addParameter(payload,'probe', "4f64c6389f230200fe2ab0aec32e7068");
nutanixProbeInvoker._addParameter(payload,'used_by_discovery', "true");
nutanixProbeInvoker._addParameter(payload,'probe_name', "Horizontal Pattern");
nutanixProbeInvoker._addParameter(payload,'excludeSshInteractivePatterns', "DB2 On Linux,WMB Flow On Unix,WMB On Unix");
nutanixProbeInvoker._addParameter(payload,'fileTracking', "{ \"maxFileSize\" : 500000, \"trackedFilesRelType\" : \"Contains::Contained by\", \"maxFilesPerCi\" : 50, \"changeCountLimitDto\" : { \"count\" : 4, \"days\" : 7 }, \"simplifiedComparisonMinSize\" : 50000, \"fileTrackingEnabled\" : true }");
return payload;
},
_sendProbe: function(midId, payload,jobName,clusterIp,configObj) {
var gr = new GlideRecord('ecc_queue');
gr.initialize();
gr.setValue('agent_correlator', configObj.discoveryStatusId);
gr.setValue('agent', 'mid.server.'+midId);
gr.setValue('source', clusterIp);
gr.setValue('name', jobName);
if (payload) {
gr.setValue('payload', payload.toString());
}
gr.setValue('topic', 'HorizontalDiscoveryProbe');
gr.setValue('queue', 'output');
gr.setValue('state', 'ready');
gr.setValue('priority', '0');
gr.insert();
},
type: 'NutanixEventHandler'
});
Sys ID
12dbb608db0e3700e7dc7c4daf9619b7