Its M Integration
Its M Integration
*                                                            *
 * Contents of file Copyright (c) Moogsoft Inc 2015           *
 *                                                            *
 *------------------------------------------------------------*
 *                                                            *
 * WARNING:                                                   *
 * THIS FILE CONTAINS UNPUBLISHED PROPRIETARY                 *
 * SOURCE CODE WHICH IS THE PROPERTY OF MOOGSOFT INC AND      *
 * WHOLLY OWNED SUBSIDIARY COMPANIES.                         *
 * PLEASE READ THE FOLLOWING AND TAKE CAREFUL NOTE:           *
 *                                                            *
 * This source code is confidential and any person who        *
 * receives a copy of it, or believes that they are viewing *
 * it without permission is asked to notify Phil Tee          *
 * on 07734 591962 or email to phil@moogsoft.com.             *
 * All intellectual property rights in this source code       *
 * are owned by Moogsoft Inc. No part of this source          *
 * code may be reproduced, adapted or transmitted in any      *
 * form or by any means, electronic, mechanical,              *
 * photocopying, recording or otherwise.                      *
 *                                                            *
 * You have been warned....so be good for goodness sake...    *
 *                                                            *
 **************************************************************/
/**
 * Overview of how the ITSM Ticketing Works.
 * This Moobot is essentially monitoring Situation custom_info for Support Groups
that need tickets.
 * The Situation Manager Moobot looks at each alert that is added to the situation
to see if it requires
 * a Ticket. If it does it checks to see if there is already a ticket for the
support group.
 *
 * A list of Support Groups that have or need tickets can be found at the key
 * ITSM.groupsWithTickets
 *
 * A list of the current Ticket Numbers can be found using the key
 * ITSM.IncidentNumbers
 *
 * Each Support Group will have its own branch under ITSM with the details needed
to create and maintain the ticket.
 * ITSM[SupportGroupName]
 *
 * Configuration Information Stored in Config.Exxon.js under ITSMTicketing
 *   autoTicketCreate : true - Setting autoTicketCreate to true causes tickets to
be created from situations when there is a SupportGroup that requires a ticket
 *   nextMoolet : "TeamsMgr" - Name of next Moolet
 *   userName : "na\\xsmoogitsm" - User name to use for creating te ticket
 *   maxAlertDescriptionSize : 1024 - Max size of any alert description
 *   maxTotalAlertDescriptionSize : 4096 - Max size of alerts added to notes
 *   createTicketScript : "scripts/createTicket.sh" - Shell script to call when a
ticket is required.
 *   workNoteTicketScript : "script/workNoteTicket.sh" - Shell Script for adding
additional work notes to ticket
 *   addTicketCIScript : "scripts/RelShipTicket.sh" - Shell script for adding CIs
to Ticket
 *   addRelatedAlertsToNotes : true - When true all alerts for situation, but not
the support group, will have their description added to Ticket Notes
 *   addRelatedCIsToTicket : true - When true all host for alerts ath are not for
the same support group, will be added to the Ticket CIs
 *
 * @file ITSMIntegration.js
 * @version 2.0
 * @author Kirk Sievers kirk@moogsoft.com
 */
/*
* For the ITSM integration for work properly there are a number of customer
specific
* properties that must be set.
*
* Most of them can be found here.
*
* The exception is that the fields that need to be populated when new ITSM requests
* are created must be defined in the situationNew() function
*/
// @requires exxon/MoobotUtils.Exxon.js */
MooBot.loadModule('exxon/MoobotUtils.Exxon.js');
var moobotUtils = new MoobotUtils();
// @requires exxon/Config.Exxon.js */
MooBot.loadModule('exxon/Config.Exxon.js');
var config = new Config();
// @requires exxon/MoobotUtils.Exxon.js */
MooBot.loadModule('BotUtility.js');
var botUtils = new BotUtility();
// Error Codes
// EITSM001 - This indicates that the situation does not have the custom_info
populated.
//             This moolet may receive the Situation before SituaitonMgr has
finished processing and adding custom_info.
//             You can ignor this as long as at soem point the ticket get created.
/**
 *    This function is called when the MooBot is first initialised in the farmd.
 *    Allows loading of required ServiceNow integration variables.
 *    The integration needs to be installed first. Only variables defined in
 *    properties section of the integration installation's def file will
 * be available.
 * @function onLoad
 */
function onLoad() {
/*
Ticket creation:
Ticket worknotes:
$1 – Incident Number
$2 – Work Notes.
Response
Sample:
{“Worl_Log”:”WLG000005729906”,”Summary”:”test”,”Notes”:”test”,”Submitter”:”na\\
xsmoogitsm”,”Full Name”:”ITSM Moog”,”Submit_date”:”2017-08-
22T17:42:142Z”,”Last_Modified_Date”:” 2017-08-22T17:42:142Z”,”Type”:”General
Information”,”Entry_Locked”:false,”Attachments”:[]}
 Add CI:
 /scripts/RelShipTicket.sh “$1” “$2”
$1 = Incident Number
$2 = CI Information.
Response Code:
JSON or Error.
{"ID":"HAS000009336844","Name":"pnhemr03.ap.xom.com","Description":"pnhemr03.ap.xom
.com","Association":"Related to","Type":"Configuration
Item","Keyword":"BMC_COMPUTERSYSTEM","Is_Business_Service":false,"Status":"Deployed
","Dependents":[]}
*/
/**
 * @function addWorkNote
 * @param {string} incidentNumber
 * @param {string} workNote
 * @param {Object} [customInfo]
 * @returns {boolean|Object} false if set to not add note or add note failed,
otherwise object containing the results
 */
function addWorkNote(incidentNumber, workNote, customInfo) {
    var fn = "addWorkNote:: ";
    var addWorkNoteProcess =
process.create(config.ITSMTicketing.workNoteTicketScript);
    // noinspection SpellCheckingInspection
    if (addWorkNoteProcess) {
        addWorkNoteProcess.arg(incidentNumber);
        addWorkNoteProcess.arg(workNote);
        if (!addWorkNoteProcessResults) {
            logger.info(fn + "Bad results from addWorkNoteProcessResults -
returning false");
            return false;
        }
    else {
        logger.warning(fn + "Process Object not created for " +
config.ITSMTicketing.workNoteTicketScript + "<< ");
        return false;
    }
/**
 * This function will update the ticket with the related CIs.
 * @function addCI
 * @param {string} incidentNumber
 * @param {string} ciName
 * @param {Object} [customInfo]
 * @returns {boolean|Object}
 */
    if (!incidentNumber || !ciName) {
        logger.warning(fn + "Incident Number and Work Note were not passed.   Could
not add work note");
        return false;
    }
    logger.info(fn + "STARTING for Incident Number " + incidentNumber + "CI Name: "
+ ciName);
var   ciHost;
var   ciFQDN;
var   addCIProcessResult;
var   FOUND = false;
 if ( ciName.indexOf("::" ) > 0 ) {
            FOUND = true;
        }
        else {
               ciFQDN = ciName;
            }
if (addCIIDProcess) {
         /*
              $1 = Incident Number
              $2 = CI Information.
         */
addCIIDProcess.arg(incidentNumber);
addCIIDProcess.arg(ciID);
                      //addCIProcessResult = addCIIDProcessResults;
                      //logger.debug(fn + "Final CI's CIID Value: '" +
addCIProcessResult + "'");
if ( FOUND === false || addCIIDResultout.ExceptionMessage )
{
    {
         var addCIFQDNProcess =
process.create(config.ITSMTicketing.addTicketCIScript);
if (addCIFQDNProcess) {
         /*
              $1 = Incident Number
              $2 = CI Information.
         */
addCIFQDNProcess.arg(incidentNumber);
         addCIFQDNProcess.arg(ciFQDN);
              var processFQDNResults = process.runToExit(addCIFQDNProcess);
                  logger.debug(fn + "CI Name: '" + ciFQDN + "'");
              var addCIFQDNProcessResults = addCIFQDNProcess.output();
                   logger.debug(fn + "FQDN Value Result : '" + addCIFQDNProcessResults +
"'");
        var addCIFQDNResultout = JSON.parse(addCIFQDNProcessResults);
        var addCIFQDNResultOutput = addCIFQDNResultout.ExceptionMessage;
if (addCIFQDNResultout.ExceptionMessage)
  {
if ( addCIFQDNResultOutput.indexOf("is not found.") > 0 ||
addCIFQDNResultOutput.indexOf("Unable to read parameter") > 0 )
        {
         var addCIHostProcess =
process.create(config.ITSMTicketing.addTicketCIScript);
if (addCIHostProcess) {
              /*
                      $1 = Incident Number
                      $2 = CI Information.
              */
addCIHostProcess.arg(incidentNumber);
addCIHostProcess.arg(ciHost);
/**
 * Creates a ticket in ITSM
 * Upon successful completion the ticket INC number is returned
 * @function createTicket
 * @param {string} situationID
 * @param {string} description
 * @param {string} urgency
 * @param {string} impact
 * @param {string} groupName
 * @param {string} alertDescriptions
 * @param {Object} customInfo
 * @param {string} service
 * @returns {boolean|string}
 */
function createTicket(situationID, description, urgency, impact, groupName,
alertDescriptions, customInfo, service, CI) {
    var fn = "createTicket::";
    logger.info(fn + "STARTING for Sit ID " + situationID + "   Desc: " +
description);
    if (!situationID) {
        logger.warning(fn + "Situation ID Parameter Not Found. Returning False");
        return false;
    }
    if (!urgency) {
        logger.warning(fn + " Urgency Parameter Not Found. Returning False");
        return false;
    }
        // Check the list of valid Urgency and Impact values.   If not in list use
default.
        if (config.ITSMTicketing.validUrgency.indexOf(urgency) === -1) {
            urgency = config.ITSMTicketing.defaultUrgency;
        }
        if (config.ITSMTicketing.validImpact.indexOf(impact) === -1) {
            impact = config.ITSMTicketing.defaultImpact;
        }
        var createTicketProcess =
process.create(config.ITSMTicketing.createTicketScript);
        if (createTicketProcess) {
            logger.info(fn + "Entered if createTicketProcess");
                /*
                $1- Username (NA\xsmoogitsm)
                $2 – Situation description
                $3 – Notes (All Alert Description with Hostname)
                $4 – Urgency
                $5 – Service name
                $6 – Assignment Group
                $7 – Situation ID
                  $8 - Impact
                  $9 - Product or Manufacturer
                  */
            logger.warning(fn + "Pre-Process ITSM productcontents:: " + service +
":::::" + JSON.stringify(customInfo));
                if (customInfo.ITSM) {
                    logger.warning(fn + "This is the current customInfo.ITSM
productcontents: '" + JSON.stringify(customInfo.ITSM) + "'");
                    if (customInfo.ITSM[groupName].ProductName &&
customInfo.ITSM[groupName].ProductName.length > 0 &&
customInfo.ITSM[groupName].ProductName !== "None") {
                     var ProductName = customInfo.ITSM[groupName].ProductName;
        ProductName = ProductName.replace(/\ /g, "\%20");
        logger.debug("This is the current customInfo.ITSM ProductName:" +
ProductName);
        productDetails = getProductDetails(ProductName);
            alertDescriptions =   moobotUtils.itsmSafe(alertDescriptions);
            // alertDescriptions = alertDescriptions.replace(/\n/g, "\\
n").replace(/\r/g, " ").replace(/\t/g, "      ");
            // alertDescriptions = alertDescriptions.replace(/\\/g, "\\\\");
            // alertDescriptions = alertDescriptions.replace(/"/g, '\\"');
            // alertDescriptions = alertDescriptions.replace(/'/g, '\\"');
            // alertDescriptions = alertDescriptions.replace(/«/g, "
").replace(/»/g, " ");
            // alertDescriptions = alertDescriptions.replace(/\\n/g, "'\\n'");
            description = description.replace(/\\/g, "\\\\");
            description = description.replace(/"/g, '\\"');
            description = description.replace(/'/g, '\\"');
         if (groupName.match(/Database Administration-Oracle/g))
         {
         if(desc)
         {
         description = desc[1];
         }
createTicketProcess.arg(CI);
            // This adds two optional parameters for product name and manufacturer
if we looked them up and found them
            if(productDetails.found === true) {
                if (productDetails.Product_Name &&
productDetails.Product_Name.length > 0) {
                    createTicketProcess.arg(productDetails.Product_Name);
                    logger.info(fn + "Product Name: " +
productDetails.Product_Name);
                }
                if (productDetails.Manufacturer &&
productDetails.Manufacturer.length > 0) {
                    createTicketProcess.arg(productDetails.Manufacturer);
                    logger.info(fn + "Manufacturer: " +
productDetails.Manufacturer);
                }
            }
            var processResults = process.runToExit(createTicketProcess);
            if (!createTicketProcessResults) {
                logger.info(fn + "Bad results from createTicketProcessResults -
returning false");
                return false;
            }
            if (!ticketResult) {
                logger.warning(fn + "Incident number not found in results " +
createTicketProcessResults);
                customInfo.ITSM[groupName].Results =
JSON.parse(createTicketProcessResults);
                return "Ticket Error";
            }
        else {
            logger.warning(fn + "Process Object not created for " +
config.ITSMTicketing.createTicketScript + "<< ");
            return false;
        }
    }
    else {
        logger.warning(fn + "Not Auto creating Ticket. SYSTEM SETTING
config.ITSMTicketing.autoTicketCreate set to false");
    }
}
function itsmSafe(textToClean){
    var result = textToClean.replace(/\n/g, "\\n").replace(/\r/g, " ").replace(/\
t/g, "      ");
    result = result.replace(/\\/g, "\\\\");
    result = result.replace(/"/g, '\\"');
    result = result.replace(/'/g, '\\"');
    result = result.replace(/«/g, " ").replace(/»/g, " ");
    result = result.replace(/\\n/g, "'\\n'");
    return result;
}
// {"Product_ID":"PDC000000069553","Product_Name":"Atrium Orchestrator
Platform","Manufacturer":"BMC Software","Tier_1":"Software","Tier_2":"Software
Product","Tier_3":"Enterprise System Management","Status":"Enabled"}
function getProductDetails(ProductName){
    var fn = "getProductDetails:: ";
    var results = {};
GetProductService.arg(ProductName);
        results = JSON.parse(processOutput);
        results.found = true;
    }
    else {
        results.found = false;
    }
    return results;
}
/**
 * Update the Situation Support Group from the Status sent from ITSM
 * Updates the Alerts for the Support Group fir the Situation as well
 * @function updateStatusFromITSM
 * @param {CEvent} situation
 * @param {Object} customInfo
 */
function processChangesFromITSM(situation, customInfo) {
    var fn = "updateStatusFromITSM:: ";
    logger.info(fn + "STARTING");
    if (!customInfo) {
        return;
    }
changeType = customInfo[incidentNumber];
                    alertIds = getAlertIdsForIncidentNumber(customInfo,
incidentNumber);
                    logger.info(fn + "Alert IDs for Inc: " + alertIds);
moobotUtils.updateAlertState(alertIds, 9);
                    supportGroup = getSupportGroupFromIncNum(customInfo,
incidentNumber);
                     if (supportGroup) {
                         customInfo.ITSM[supportGroup].ITSMLastStatus = "Resolved";
                         if (!customInfo.ITSM.AlertsResolved) {
                             customInfo.ITSM.AlertsResolved = [];
                         }
                         customInfo.ITSM.AlertsResolved =
botUtils.uniqArray(moobotUtils.pushArray(customInfo.ITSM.AlertsResolved,
alertIds));
                     }
                     result = true;
                     sigChanged = true;
                     customInfo[incidentNumber] = customInfo[incidentNumber] + "-
Processed";
                 var ITSM = {};
                ITSM = customInfo.ITSM;
                         var newAssignmentGroup = supportGroup + "-Resolved";
                         logger.debug(fn + "GroupsWithTickets before change: " +
ITSM.groupsWithTickets);
                         ITSM.groupsWithTickets =
ITSM.groupsWithTickets.filter(function(i){return i != supportGroup;});
                         ITSM.groupsWithTickets.push(newAssignmentGroup);
                         logger.debug(fn + "GroupsWithTickets after change: " +
ITSM.groupsWithTickets)
                         logger.debug(fn + "ITSM Before change: " +
JSON.stringify(ITSM));
                         ITSM[newAssignmentGroup] = ITSM[supportGroup];
                         logger.debug(fn + "ITSM After Add New Group: " +
JSON.stringify(ITSM));
                       // var AG = "\"" + supportGroup + "\"";
                         delete ITSM[supportGroup];
                  logger.debug(fn + "ITSM After Remove Old Group: " +
ITSM[supportGroup]);
                         logger.debug(fn + "ITSM After Remove Old Group: " +
JSON.stringify(ITSM));
                // * * Step 5 - Update Situation Record
                         logger.debug(fn + "ITSM Object:" + ITSM);
                         customInfo.ITSM = ITSM;
                         situation.setCustomInfo(customInfo);
                         moogdb.updateSituation(situation);
                      break;
              case "Cancelled":
                          logger.info(fn + "Status Change From ITSM. New Status:
Resolved");
                      alertIds = getAlertIdsForIncidentNumber(customInfo,
incidentNumber);
                      logger.info(fn + "Alert IDs for Inc: " + alertIds);
moobotUtils.updateAlertState(alertIds, 9);
                      supportGroup = getSupportGroupFromIncNum(customInfo,
incidentNumber);
                    if (supportGroup) {
                         customInfo.ITSM[supportGroup].ITSMLastStatus = "Resolved";
                         if (!customInfo.ITSM.AlertsResolved) {
                             customInfo.ITSM.AlertsResolved = [];
                         }
                         customInfo.ITSM.AlertsResolved =
botUtils.uniqArray(moobotUtils.pushArray(customInfo.ITSM.AlertsResolved,
alertIds));
                    }
                    result = true;
                    sigChanged = true;
                    customInfo[incidentNumber] = customInfo[incidentNumber] + "-
Processed";
                 var ITSM = {};
                ITSM = customInfo.ITSM;
                         var newAssignmentGroup = supportGroup + "-Cancelled";
                         logger.debug(fn + "GroupsWithTickets before change: " +
ITSM.groupsWithTickets);
                         ITSM.groupsWithTickets =
ITSM.groupsWithTickets.filter(function(i){return i != supportGroup;});
                         ITSM.groupsWithTickets.push(newAssignmentGroup);
                         logger.debug(fn + "GroupsWithTickets after change: " +
ITSM.groupsWithTickets)
                         logger.debug(fn + "ITSM Before change: " +
JSON.stringify(ITSM));
                         ITSM[newAssignmentGroup] = ITSM[supportGroup];
                         logger.debug(fn + "ITSM After Add New Group: " +
JSON.stringify(ITSM));
                         delete ITSM[supportGroup];
                         logger.debug(fn + "ITSM After Remove Old Group: " +
JSON.stringify(ITSM));
                // * * Step 5 - Update Situation Record
                         logger.debug(fn + "ITSM Object:" + ITSM);
                         customInfo.ITSM = ITSM;
                         situation.setCustomInfo(customInfo);
                         moogdb.updateSituation(situation);
                    alertIds = getAlertIdsForIncidentNumber(customInfo,
incidentNumber);
moobotUtils.updateAlertState(alertIds, 9);
                    supportGroup = getSupportGroupFromIncNum(customInfo,
incidentNumber);
                  var ITSM = {};
                ITSM = customInfo.ITSM;
                         var newAssignmentGroup = supportGroup + "-Cancelled";
                         logger.debug(fn + "GroupsWithTickets before change: " +
ITSM.groupsWithTickets);
                         ITSM.groupsWithTickets =
ITSM.groupsWithTickets.filter(function(i){return i != supportGroup;});
                         ITSM.groupsWithTickets.push(newAssignmentGroup);
                         logger.debug(fn + "GroupsWithTickets after change: " +
ITSM.groupsWithTickets)
                         logger.debug(fn + "ITSM Before change: " +
JSON.stringify(ITSM));
                         ITSM[newAssignmentGroup] = ITSM[supportGroup];
                         logger.debug(fn + "ITSM After Add New Group: " +
JSON.stringify(ITSM));
                       // var AG = "\"" + supportGroup + "\"";
                         delete ITSM[supportGroup];
                         logger.debug(fn + "ITSM After Remove Old Group: " +
ITSM[supportGroup]);
                         logger.debug(fn + "ITSM After Remove Old Group: " +
JSON.stringify(ITSM));
                // * * Step 5 - Update Situation Record
                         logger.debug(fn + "ITSM Object:" + ITSM);
                         customInfo.ITSM = ITSM;
                         situation.setCustomInfo(customInfo);
                         moogdb.updateSituation(situation);
                     if (supportGroup) {
                         customInfo.ITSM[supportGroup].ITSMLastStatus = "Closed";
                         if (!customInfo.ITSM.AlertsClosed) {
                             customInfo.ITSM.AlertsClosed = [];
                         }
                         customInfo.ITSM.AlertsClosed =
botUtils.uniqArray(moobotUtils.pushArray(customInfo.ITSM.AlertsClosed, alertIds));
                     }
                     result = true;
                     sigChanged = true;
                     customInfo[incidentNumber] = customInfo[incidentNumber] + "-
Processed";
                       if (moobotUtils.checkAllSigAlertState(sigId, 9) === true) {
                           logger.info(fn + "Sit: '" + sigId + "' All Alerts Closed.
Closing Situation");
                           // Close the Situation
                           moogdb.closeSituation(sigId, moogdb.CLOSE_UNUSED_ALERTS);
                    }
                    else {
                        logger.info(fn + "Sit: '" + sigId + "' NOT All Alerts
Closed. Can't Close Situation");
                    }
                    break;
                      break;
                  default:
                      logger.warning(fn + "Unknown ITSM Ticket Status.   Not handling
change.");
              }
        }
              delete(customInfo[agIncidentNumber]);
              sigChanged = true;
moobotUtils.updateAlertSupportGroup(ITSM[newAssignmentGroup].AlertsHavingTickets,
newAssignmentGroup);
customInfo.ITSM = ITSM;
                sigChanged = true;
            }
        }
    }
sigTotalAlerts = situation.value("total_alerts");
        // Otherwise Resolve the Situation if all the alerts have been resolved
        // TODO this is only working if all the alerts are for the same support
group and there is only the one support group.
        else if (customInfo.ITSM.AlertsResolved &&
customInfo.ITSM.AlertsResolved.length > 0) {
            logger.info(fn + "Total Resolved Alerts: " +
customInfo.ITSM.AlertsResolved.length);
sigTotalAlerts = situation.value("total_alerts");
/**
 * @function getSupportGroupFromIncNum
 * @param {Object} customInfo
 * @param {string} incidentNumber
 * @returns {string| boolean}supportGroup
 */
function getSupportGroupFromIncNum(customInfo, incidentNumber) {
    var fn = "getSupportGroupFromIncNum ";
logger.info(fn + "STARTING");
    if (!customInfo || !incidentNumber) {
        return false;
    }
    if (customInfo.ITSM && customInfo.ITSM.groupsWithTickets &&
customInfo.ITSM.groupsWithTickets.length > 0) {
        logger.info(fn + "Groups with tickets: " +
customInfo.ITSM.groupsWithTickets);
        for (var gIdx = 0; gIdx < customInfo.ITSM.groupsWithTickets.length; gIdx++)
{
            var currentGroup = customInfo.ITSM.groupsWithTickets[gIdx];
            logger.info(fn + "currentGroup: " + currentGroup);
            if (customInfo.ITSM[currentGroup] &&
                customInfo.ITSM[currentGroup].IncidentNumber &&
                customInfo.ITSM[currentGroup].IncidentNumber === incidentNumber) {
                supportGroup = currentGroup;
                logger.info(fn + "Support Group for Incident Number: " +
incidentNumber + " is: " + supportGroup);
            }
        }
    }
    else {
        logger.info(fn + "There are no Support groups for Situation");
    }
    return supportGroup;
}
/**
 * @function getAlertIdsForIncidentNumber
 * @param {Object} customInfo
 * @param {string} incidentNumber
 * @returns {Array} Alert IDs
 */
function getAlertIdsForIncidentNumber(customInfo, incidentNumber) {
    var fn = "getAlertIdsForIncidentNumber:: ";
    logger.debug(fn + "STARTING");
    if (!customInfo || !incidentNumber) {
        return alertIds;
    }
    logger.info(fn + "Alert IDs for Support Group '" + supportGroup + "' IDs: " +
alertIds);
return alertIds;
/**
 * Called when a situation is Created or Updated
 * Reads the Support Groups that have or need tickets from
customInfo.ITSM.groupsWithTickets
 * @function situationProcess
 * @param {CEvent} inBoundSituation
 */
function situationProcess(inBoundSituation) {
    var fn = "situationProcess:: ";
    var sigId = inBoundSituation.value('sig_id');
    if (!customInfo) {
        logger.warning(fn + "Situation Does not have custom_info. Waiting for
SituationMgr to add. Exiting ITSM Integration Moobot. EITSM001");
        return;
    }
if (customInfo.ITSM.groupsWithTickets) {
                if (customInfo.ITSM.groupsWithTickets.length > 0) {
                    logger.debug(fn + "Number of groups with tickets: '" +
customInfo.ITSM.groupsWithTickets.length + "'");
                                 if
(config.ITSMTicketing.includeAllAlertsInInitialTicketNotes === true) {
                                    logger.debug(fn + "CALLING
getRemainingincidentNotes(" + sitAllAlertIds.alert_ids + ", " + alertIds + ", " +
incidentNotes + ")");
                                    if(sitAllAlertIds.alert_ids.length >
alertIds.length){
                                        // Get the Alert IDs that are in the
Situation but not for this group
                                        var remainingAlertIds =
botUtils.arrayDifference(sitAllAlertIds.alert_ids, alertIds);
                                        logger.debug(fn + "Remaining Alert IDs to
Process: " + remainingAlertIds);
                                        incidentNotes +=
config.ITSMTicketing.ticketLineBreak + config.ITSMTicketing.ticketLineFeed;
                                        incidentNotes +=
getAlertDescriptions(remainingAlerts)+ config.ITSMTicketing.ticketLineFeed;
                                    }
                                }
                                incidentNotes +=
config.ITSMTicketing.ticketLineBreak + config.ITSMTicketing.ticketLineFeed + "The
Moogsoft situation id = " + sigId + config.ITSMTicketing.ticketLineFeed;
                                    customInfo.ITSM[groupName].IncidentNumber =
incidentNumber;
                                    if (!customInfo.ITSM.IncidentNumbers) {
                                        customInfo.ITSM.IncidentNumbers = [];
                                    }
customInfo.ITSM.IncidentNumbers.push(incidentNumber);
                                    addTicketNumberToAlerts(alertIds,
incidentNumber, situation.value("sig_id"));
                                    alertHosts =
customInfo.ITSM[groupName].HostsToAdd;
customInfo.ITSM[groupName].HostsAdded.concat(customInfo.ITSM[groupName].HostsToAdd)
;
                                        }
                                        else {
                                            customInfo.ITSM[groupName].HostsAdded =
customInfo.ITSM[groupName].HostsToAdd;
                                        }
                                        customInfo.ITSM[groupName].HostsToAdd = [];
                                    }
alerts2WorkNotes(incidentNumber,incidentAlerts);
                                }
                                situationChange = true;
                            }
alerts2WorkNotes(customInfo.ITSM[groupName].IncidentNumber,incidentAlerts);
addCI(customInfo.ITSM[groupName].IncidentNumber, alertHosts[hIdx]);
                                        }
                                        if
(customInfo.ITSM[groupName].HostsAdded.length > 0) {
customInfo.ITSM[groupName].HostsAdded.concat(customInfo.ITSM[groupName].HostsToAdd)
;
                                        }
                                        else {
                                            customInfo.ITSM[groupName].HostsAdded =
customInfo.ITSM[groupName].HostsToAdd;
                                        }
                                        customInfo.ITSM[groupName].HostsToAdd = [];
                                    }
                                       //   * * Step 6 - Update group with success and
save
                                       customInfo.ITSM[groupName].TicketStatus =
"Updated";
                                    customInfo.ITSM[groupName].AlertsHavingTickets
= customInfo.ITSM[groupName].AlertsHavingTickets.concat(alertIds);
                                    customInfo.ITSM[groupName].AlertsHavingTickets
= botUtils.uniqArray(customInfo.ITSM[groupName].AlertsHavingTickets);
                                    customInfo.ITSM[groupName].AlertsNeedingTickets
= [];
                                       situationChange = true;
                                   }
                             }
                        }
                        else {
                             logger.info(fn + "TicketStatus property not found for
group '" + groupName + "'");
                        }
                    }
                    if(situationChange === true){
                        situation.setCustomInfo(customInfo);
                        moogdb.setSigCustomInfo(situation);
                    }
                }
                else {
                    logger.info(fn + "The group count for
custom_info.ITSM.groupsWithTickets was zero");
                }
            }
            else {
                logger.info(fn + "There was not a
custom_info.ITSM.groupsWithTickets property. Exiting moobot");
            }
        }
        else {
            logger.info(fn + "custom_info did not contain ITSM. Exiting Moobot");
            return;
        }
    }
    else {
        // Don't create the ITSM ticket
        logger.warning(fn + "Checking if tickets are required. SYSTEM SETTING
config.ITSMTicketing.autoTicketCreate set to false");
    }
    // Check the situation to see if there have been any changes from ITSM and
update the situation and alerts
    if (customInfo.ITSM && customInfo.ITSM.IncidentNumbers &&
customInfo.ITSM.IncidentNumbers.length > 0) {
        logger.info(fn + "Sending custom_info over to updateStatusFromITSM");
        processChangesFromITSM(situation, customInfo);
    }
    situation = moogdb.getSituation(sigId);
    situation.forward(config.ITSMTicketing.nextMoolet);
    logger.info(fn + "ENDING Sending situation to next moolet: " +
config.ITSMTicketing.nextMoolet);
    inBoundSituation.forward(this);
}
/**
 * @function alerts2WorkNotes
 * @param {string} incidentNumber
 * @param {Object} incidentAlerts
 * @returns {boolean|Object} false if set to not add note or add note failed,
otherwise object containing the results
 */
function alerts2WorkNotes(incidentNumber, incidentAlerts) {
    var fn = "addWoralerts2WorkNoteskNote:: ";
    var results = {};
    if (!incidentAlerts) {
        logger.warning(fn + "Missing parameter incidentAlerts");
        return results;
    }
    if (!incidentAlerts.alertIds) {
        logger.warning(fn + "incidentAlerts is missing alertIds");
        return results;
    }
    if (incidentAlerts.alertIds.length < 1) {
        logger.warning(fn + "incidentAlerts.alertIds length is: " +
incidentAlerts.alertIds.length);
        return results;
    }
    logger.debug(fn + "Processing Alert IDs: " + incidentAlerts.alertIds);
/*
<Alert Description>
Host: <Host>
AlertID:<moog alert ID
-----------------------------------
<Alert Description>
Host: <Host>
AlertID:<moog alert ID
-----------------------------------
<Alert Description>
Host: <Host>
AlertID:<moog alert ID
-----------------------------------
The Moogsoft situation id = <Situation ID>
 */
/**
 * *    {
 *   alertIds [12345,12346],
 *   12345 : {CEvent},
 *   12346 : {CEvent}
 *   }
 * @function getAlertDescriptions
 * @param {Object} incidentAlerts
 * @returns {string|boolean}
 */
function getAlertDescriptions(incidentAlerts) {
    var fn = "getAlertDescriptions:: ";
    var results = "";
    if (!incidentAlerts) {
        logger.warning(fn + "Missing parameter incidentAlerts");
        return results;
    }
    if (!incidentAlerts.alertIds) {
        logger.warning(fn + "incidentAlerts is missing alertIds");
        return results;
    }
    if (incidentAlerts.alertIds.length < 1) {
        logger.warning(fn + "incidentAlerts.alertIds length is: " +
incidentAlerts.alertIds.length);
        return results;
    }
    logger.debug(fn + "Processing Alert IDs: " + incidentAlerts.alertIds);
            if (cIdx > 0) {
                alertDescForIncident += config.ITSMTicketing.ticketLineBreak +
config.ITSMTicketing.ticketLineFeed;
            }
                  alertDescForIncident += "Please see Work Detail for all Alerts
associated with this Incident ID" + config.ITSMTicketing.ticketLineFeed;
            alertDescForIncident +=
"-----------------------------------------------------------------" +
config.ITSMTicketing.ticketLineFeed;
            alertDescForIncident +=
botUtils.maxChars(description,config.ITSMTicketing.maxAlertDescriptionSize) +
config.ITSMTicketing.ticketLineFeed;
            alertDescForIncident += "Class: " + class +
config.ITSMTicketing.ticketLineFeed;
            alertDescForIncident += "Host: " + host +
config.ITSMTicketing.ticketLineFeed;
            alertDescForIncident += "AlertID: " + alert_id +
config.ITSMTicketing.ticketLineFeed;
            // var alertDescForIncident = "Alert " + alert.value("alert_id") + " :
Open : " + moobotUtils.maxChars(alert.value("source") + " : " +
alert.value("description"), config.ITSMTicketing.maxalertDescForIncidentSize);
incidentAlertDescription += alertDescForIncident;
/**
 * from an array of alert IDs returns an object of Alerts by key=alert_id
 * {
 *   alertIds [12345,12346],
 *   12345 : {CEvent},
 *   12346 : {CEvent}
 *   }
 * @function getAlerts
 * @param {Array} alert_ids
 * @param {number} limit
 * @returns {Object}
 */
function getAlerts(alert_ids,limit) {
    var fn= "getAlerts:: ";
    var alerts={};
    alerts.alertIds = [];
    if(!alert_ids){
        logger.debug(fn + "AlertIDs paramiter is required.");
        return alerts;
    }
            if(alert) {
                var alert_id = alert.value("alert_id");
                alerts[alert_id] = alert;
    return alerts;
}
/**
 * @function addTicketNumberToAlerts
 * @param {Array} alertIds
 * @param {string} incidentNumber
 * @param {string} sitID
 */
function addTicketNumberToAlerts(alertIds, incidentNumber, sitID) {
    var fn = "addTicketNumberToAlerts:: ";
    if (!alertIds) {
        logger.debug(fn + "alertIds Not Valid");
        return false;
    }
    if (!incidentNumber) {
        logger.debug(fn + "incidentNumber Not Valid");
        return false;
    }
    if (alertIds && alertIds.length > 0 && incidentNumber) {
        logger.info(fn + "Adding incident Number: '" + incidentNumber + "' to
Alerts '" + alertIds + "' Total Alerts: '" + alertIds.length + "'");
        var custom_info = {};
        custom_info.ITSM = {};
        custom_info.ITSM.TicketNumber = incidentNumber;
        custom_info.ITSM.SituationID = sitID;
        for (var aIdx = 0; aIdx < alertIds.length; aIdx++) {
            logger.debug(fn + "AlertID: '" + alertIds[aIdx] + "' - TicketNumber: '"
+ incidentNumber + "'");
            moogdb.setAlertCustomInfo(alertIds[aIdx], custom_info, true);
        }
        return true;
    }
    else {
        // the required parameters were not present
        return false;
    }
}
events.onEvent('situationProcess', constants.eventType('Sig')).listen();
events.onEvent('situationProcess', constants.eventType('SigUpdate')).listen();