Thursday, February 22, 2024

 startVirtualComputerCheck():


Initiates the virtual computer check and sets the virtual field to true if certain conditions are met.

Checks if the configuration item is a Solaris Zone, VMWare, HyperV, or falls under credentialless discovery.

Establishes relationships between virtual machines (VMs), instances, and hypervisors.

isSolarisZone():


Checks if the configuration item is a Solaris Zone based on its system class name, correlation_id, and specific conditions.

isVMWare():


Checks if the configuration item is a VMWare VM based on its serial number.

isHyperV():


Checks if the configuration item is a HyperV VM based on its serial number and specific conditions.

handleSolariZone():


Handles the case when the configuration item is identified as a Solaris Zone by querying and setting the corresponding instance.

isCredentialless():


Checks if the discovery is credentialless and attempts to reconcile with a VMWare VM based on IP address.

handleVMWare():


Handles the case when the configuration item is identified as a VMWare VM by querying and setting the corresponding instance.

commonVMWareHandling():


Common handling for VMWare instances and guests, filtering out reconciled relationships.

handleHyperV():


Handles the case when the configuration item is identified as a HyperV VM.

findVMWareByImage():


Finds a VMWare instance based on the relationship with the provided instance.

reconcileRelationVMtoHyperVisor():

Reconciles relationships between VM and HyperVisor, creating or correcting relationships.

setIsVirtualForCloudIPs():

Sets the virtual field to true based on specific IP address patterns.

This script seems to be part of a larger system responsible for identifying and managing virtualized resources within a CMDB. The comments in the code provide insights into the logic and reasoning behind various decisions.

[2:09 PM, 2/21/2024] Parth New ServiceNow Support: function isVMWare() {: This line starts the definition of the isVMWare function.


if (!fVMGr.serial_number.hasValue()): Checks if the serial number of a virtual machine (fVMGr) has a value. If not, it returns false.


return false;: If the serial number is empty, the function immediately returns false.


if (!fVMGr.serial_number.toLowerCase().startsWith("vmware-")): Checks if the lowercase version of the serial number starts with the string "vmware-". This is a common pattern for VMware serial numbers. If not, it returns false.


return false;: If the serial number doesn't match the expected pattern, the function returns false.


return true;: If the serial number has a value and starts with "vmware-", the function returns true, indicating that the device is recognized as a VMware virtual machine.


}: Closes the isVMWare function.


function isHyperV() {: This line starts the definition of the isHyperV function.


var serialNumber = fVMGr.serial_number;: Stores the serial number of the virtual machine in the variable serialNumber for easier reference.


if (!serialNumber.hasValue()): Checks if the serial number has a value. If not, it returns false.


return false;: If the serial number is empty, the function immediately returns false.


var instGr = new GlideRecord("cmdb_ci_hyper_v_instance");: Creates a new GlideRecord object for the "cmdb_ci_hyper_v_instance" table, which likely stores information about Hyper-V instances.


var serials = ['chassis_serial', 'bios_serial', 'baseboard_serial'];: Defines an array serials containing three serial-related fields in the "cmdb_ci_hyper_v_instance" table.


return serials.some( ... );: Uses the some function to iterate over the serials array and check if the serial number matches any of these fields.


function(serial) { ... }: Defines an anonymous function that takes a serial field as a parameter.


instGr.initialize();: Initializes the GlideRecord object for each iteration.


if (instGr.get(serial, serialNumber)) { ... }: Attempts to retrieve a record from the "cmdb_ci_hyper_v_instance" table where the specified serial field matches the virtual machine's serial number.


fInstanceGr = instGr;: If a matching record is found, it assigns the GlideRecord object to the variable fInstanceGr.


return true;: If a match is found for any serial field, the anonymous function returns true, and the some function stops iterating.


});: Closes the anonymous function and the some function.


}: Closes the isHyperV function.


In summary, these functions determine whether a device is a VMware or Hyper-V virtual machine based on its serial number, returning true if it matches the respective criteria and false otherwise. The Hyper-V function also sets a GlideRecord object (fInstanceGr) if a match is found.

[2:13 PM, 2/21/2024] Parth New ServiceNow Support: let's break down each function in detail:


1. function handleSolariZone() {

javascript


var matchingId = fVMGr.correlation_id.substring(5);

var gr = new GlideRecord('cmdb_ci_solaris_instance');

gr.addQuery('correlation_id', matchingId);

gr.query();

if (gr.next())

    fInstanceGr = gr;


This function appears to handle Solaris zones. Here's a step-by-step explanation:


matchingId = fVMGr.correlation_id.substring(5);: Extracts a substring from the correlation_id of the current virtual machine record (fVMGr). It starts from the 6th character, effectively excluding the first 5 characters.


gr = new GlideRecord('cmdb_ci_solaris_instance');: Creates a new GlideRecord object for the "cmdb_ci_solaris_instance" table.


gr.addQuery('correlation_id', matchingId);: Adds a query condition to the GlideRecord, filtering records where the correlation_id matches the previously derived matchingId.


gr.query();: Executes the query on the GlideRecord.


if (gr.next()) fInstanceGr = gr;: If there's at least one record matching the criteria, it advances to the first matching record (gr.next()) and assigns it to the variable fInstanceGr.


[2:14 PM, 2/21/2024] Parth New ServiceNow Support: 2. function isCredentialless() {

javascript


var potentialVmInstances, potentialGuests;


if (!current.ip_address || !current.ip_address.changes() || current.discovery_source != 'CredentiallessDiscovery')

    return;


potentialVmInstances = new GlideRecord('cmdb_ci_vmware_instance');

potentialVmInstances.addQuery('ip_address', current.ip_address);

potentialVmInstances.setLimit(2);

potentialVmInstances.query();


potentialGuests = new GlideRecord('cmdb_ci_computer');

potentialGuests.addQuery('ip_address', current.ip_address);

potentialGuests.addQuery('sys_id', '!=', current.sys_id);

potentialGuests.setLimit(2);

potentialGuests.query();


commonVMWareHandling(potentialVmInstances, potentialGuests);


return !!fInstanceGr;

This function appears to check if the current record is being created by credentialless discovery and attempts to reconcile it with a VMWare VM based on IP. Here's a detailed breakdown:


Initial Variable Declarations:


var potentialVmInstances, potentialGuests;: Declares two GlideRecord variables for potential VMware instances and potential computer guests.

Credentialless Discovery Check:


if (!current.ip_address || !current.ip_address.changes() || current.discovery_source != 'CredentiallessDiscovery') return;: Checks if the IP address is empty, hasn't changed, or if the discovery source is not 'CredentiallessDiscovery'. If any of these conditions are met, the function returns early.

Query Potential VMware Instances:


potentialVmInstances = new GlideRecord('cmdb_ci_vmware_instance');: Creates a GlideRecord object for the "cmdb_ci_vmware_instance" table.

potentialVmInstances.addQuery('ip_address', current.ip_address);: Adds a query condition to find VMware instances with the same IP address as the current record.

potentialVmInstances.setLimit(2);: Sets a limit of 2 records to retrieve.

potentialVmInstances.query();: Executes the query.

Query Potential Computer Guests:


potentialGuests = new GlideRecord('cmdb_ci_computer');: Creates a GlideRecord object for the "cmdb_ci_computer" table.

potentialGuests.addQuery('ip_address', current.ip_address);: Adds a query condition to find computer records with the same IP address as the current record.

potentialGuests.addQuery('sys_id', '!=', current.sys_id);: Excludes the current record from the query.

potentialGuests.setLimit(2);: Sets a limit of 2 records to retrieve.

potentialGuests.query();: Executes the query.

Common VMware Handling Function:


commonVMWareHandling(potentialVmInstances, potentialGuests);: Calls a common function (commonVMWareHandling) with the potential VMware instances and computer guests as parameters.

Return Statement:


return !!fInstanceGr;: Returns a boolean indicating whether fInstanceGr has a value. If it has a value, it returns true; otherwise, it returns false.

[3:01 PM, 2/21/2024] Parth New ServiceNow Support: This JavaScript function, named isHyperV, checks whether a device (presumably a virtual machine) is a Hyper-V virtual machine based on its serial number. Let's break down each part of the function:



function isHyperV() {

    var serialNumber = fVMGr.serial_number;


    if (!serialNumber.hasValue())

        return false;


    var instGr = new GlideRecord("cmdb_ci_hyper_v_instance");

    var serials = ['chassis_serial', 'bios_serial', 'baseboard_serial'];


    return serials.some(

        function(serial) {

            instGr.initialize();

            if (instGr.get(serial, serialNumber)) {

                fInstanceGr = instGr;

                return true;

            }

        }

    );

}

var serialNumber = fVMGr.serial_number;: Retrieves the serial number of the virtual machine from the fVMGr object and stores it in the variable serialNumber.


if (!serialNumber.hasValue()) return false;: Checks if the serialNumber has a value. If not, it immediately returns false, indicating that the device is not a Hyper-V virtual machine.


var instGr = new GlideRecord("cmdb_ci_hyper_v_instance");: Creates a new GlideRecord object for the "cmdb_ci_hyper_v_instance" table, suggesting that information about Hyper-V instances is stored in this table.


var serials = ['chassis_serial', 'bios_serial', 'baseboard_serial'];: Defines an array serials containing three types of serial numbers associated with Hyper-V instances.


return serials.some(...);: Uses the some function to iterate over the serials array and check if any of the Hyper-V serial numbers match the virtual machine's serial number.


function(serial) { ... }: Defines an anonymous function that takes a serial type as a parameter.


instGr.initialize();: Initializes the GlideRecord object instGr for each iteration.


if (instGr.get(serial, serialNumber)) { ... }: Attempts to retrieve a record from the "cmdb_ci_hyper_v_instance" table where the specified serial field matches the virtual machine's serial number.


fInstanceGr = instGr;: If a matching record is found, it assigns the GlideRecord object to the variable fInstanceGr.


return true;: If a match is found for any serial field, the anonymous function returns true, and the some function stops iterating.


});: Closes the anonymous function and the some function.


The entire function returns the result of the some function, indicating whether the virtual machine is identified as a Hyper-V instance based on the provided serial numbers. If true, it sets fInstanceGr to the matching GlideRecord object. If false, it indicates that the device is not recognized as a Hyper-V virtual machine.


Tuesday, February 20, 2024

DiscoveryFunctions Script Include

 var DiscoveryFunctions = Class.create();


(function() {


var relTypes = { };


DiscoveryFunctions.prototype = {

    initialize: function() {

    },

getDiscoverySource: function() {

var gr = new GlideRecord("sys_properties");

if(gr.get("name", "glide.discovery.source_name"))

return gr.getValue('value');

return "";

},


    getScheduleRecord: function() {

        var statusGR = this.getStatusRecord();

        if (!statusGR)

            return;


        var gr = new GlideRecord('discovery_schedule');

        if (statusGR.dscheduler)

            gr.get('sys_id', statusGR.dscheduler);

        return gr;

    },


    getStatusRecord: function() {

        var statusSysId = g_probe.getCorrelator();

        if (gs.nil(statusSysId)) {

            if (typeof agent_correlator != 'string' && agent_correlator)

                statusSysId = agent_correlator;

            else if (current) {

                if (current.agent_correlator)

                    statusSysId = current.agent_correlator;

                else if (current.getTableName() == "discovery_status")

                    return current;

            }

        }


        if (!statusSysId)

            return null;


        var gr = new GlideRecord('discovery_status');

        if (statusSysId)

            gr.get('sys_id', statusSysId);

        return gr;

    },


    getDiscoveryType: function(statusID) {

        var statusGR = new GlideRecord('discovery_status');

        statusGR.get(statusID);

        var schedGR = new GlideRecord('discovery_schedule');

        schedGR.get(statusGR.dscheduler);

        return schedGR.discover;

    },


    getService: function(port) {

        var gr = new GlideRecord("cmdb_ip_service");

        if (!gr.get("port", port)) {

            gr.initialize();

            gr.setValue("port", port);

            gr.setValue("name", "unknown - port(" + port + ")");

            gr.insert();

        }


        return gr;

    },


    isInRange: function(ip) {

        var gr = this.getStatusRecord();

        if (gr != null) {

            var hostList = gr.scratchpad.host_list;


            if (hostList) {

                var hosts = StringUtil.split(hostList, ",");

                if (hosts.contains(ip))

                    return true;

            }


            return SncDiscoveryRangesDB.inRanges(ip, gr.dscheduler);

        }


        return false;

    },


    getXMLMemoryTable: function(tableName, doc, path) {

        var result = null;

        try {

            result = GlidesoftXMLMemoryTable.getFromDocAndXPath(tableName, doc, path);

        } catch (iae) {

            // do nothing; we'll return a null...

        }

        return result;

    },


    getFieldsThatChanged: function(gr) {

        var changes = [];


        if (gr == null || !gr.isValid())

            return changes;


        var gru = GlideScriptRecordUtil.get(gr);

        var ignoreables = new Packages.java.util.ArrayList();

        ignoreables.add("last_discovered");


        var whatChanged = gru.getChangedFields(ignoreables);

        for (var i = 0; i < whatChanged.size(); i++) {

            var f = whatChanged.get(i);

            changes.push(f);

        }


        return changes;

    },


    updatedHistory: function(gr, sensor, eccID) {

        var fieldsChanged = this.getFieldsThatChanged(gr);

        if (fieldsChanged.length > 0)

            g_device.log("Updated device fields " + fieldsChanged.join(", "), sensor, eccID);

    },


/*

     *  Return the sys_id of the relationship created. Otherwise return null or undefined.

     */

createRelationshipFromSysIds: function(parentId, childId, pDescription, cDescription) {

        if (JSUtil.nil(parentId) || JSUtil.nil(childId))

            return;

        if (!this.validCISysId(parentId) || !this.validCISysId(childId)) {

return;

}


        if (!cDescription && pDescription.indexOf("::") > -1) {

            var parts = pDescription.split("::");

            pDescription = parts[0];

            cDescription = parts[1];

        }


var ECMDBUtil = SncECMDBUtil;

        return ECMDBUtil.createCIRelationship('cmdb_rel_ci', parentId, childId, pDescription, cDescription);

    },


    // Validate sysid

validCISysId: function(sysID) {

// Case 1: Check for null sys id

if (gs.nil(sysID)) {

gs.log('Invalid Rel CI Record :: Null SysID');

return false;

}


//extracting only alphanumeric and comparing 32 chars

if (sysID.match(/[0-9a-f]{32}/) == sysID) {

return true;

} else {

// Case 3:SysID is not null

// but it is not a valid sysID by its strig format [Alphanumeric and exactly 32 chars]

gs.log('Invalid Rel CI Record :: Invalid SysID(Regex only) :SysID ' + sysID);

return false;

}

},


    //

    // Args:    parent <pDescription> child   /    child <cDescription> parent

    // Example: vmware   Runs on      sanops  /    sanops    Runs       vmware

    // parent, child input can either be GlideRecord or sys_id

    //

    createRelationship: function(parent, child, pDescription, cDescription) {

        if (JSUtil.nil(parent) || JSUtil.nil(child))

            return;


        var parentId = parent;

        var childId  = child;


        //If parent or child is a GlideRecord object, we need to extract the sys_id

        if (parent instanceof GlideRecord)

            parentId = parent.sys_id;

        if (child instanceof GlideRecord)

            childId  = child.sys_id;


return this.createRelationshipFromSysIds(parentId, childId, pDescription, cDescription);

    },


    /*

     *  Return the sys_id of the relationship if found or created. Otherwise return null or undefined.

     */

    createRelationshipIfNotExists: function(parent, child, descriptor, ensureUnique) {

        var result = this.relationshipExists(parent, child, descriptor);

        if (JSUtil.notNil(result))

            return result;


        var createdRelationship =  this.createRelationship(parent, child, descriptor);


//checking unique for the newly created relationship

if (ensureUnique)

this.deleteRelationshipIfMultipleExists(parent, child, descriptor);


return createdRelationship;

    },


    /*

     *  Checks to see if a relationship already exists

     */

    relationshipExists: function(parent, child, descriptor) {

        if (JSUtil.nil(parent) || JSUtil.nil(child) || JSUtil.nil(descriptor))

            return;


        var parentId = parent;

        var childId  = child;


        //If parent or child is a GlideRecord object, we need to extract the sys_id

        if (parent instanceof GlideRecord)

            parentId = parent.sys_id;

        if (child instanceof GlideRecord)

            childId  = child.sys_id;


        var relationType = this.findCIRelationshipType("cmdb_rel_type", descriptor);


        var gr = new GlideRecord("cmdb_rel_ci");

        gr.addQuery("parent", parentId);

        gr.addQuery("child", childId);

        gr.addQuery("type", relationType);

        gr.query();

        if (gr.next())

            return gr;


        return;

    },


/*

     *  Deleted duplicate relationship from cmdb_rel_ci

     */

deleteRelationshipIfMultipleExists: function  (parent, child, relTypeName) {

var gr = new GlideRecord('cmdb_rel_ci');

var relTypeId = this.findCIRelationshipType('cmdb_rel_type', relTypeName);


gr.addQuery('parent', parent);

gr.addQuery('child', child);

gr.addQuery('type', relTypeId);

gr.orderBy('sys_id');

gr.query();


if (gr.getRowCount() > 1) {

gs.info('Duplicate relationship %% ' + relTypeName + ' exists between the parent  ' + parent + ' and child ' + child);


// Don't allow exact duplicates.  We'll keep the one with the lowest sys_id

// to avoid a race condition where two threads insert a record at the same

// time and both decide to delete it.

gr.next();


// Delete duplicate record

while (gr.next()) {

gr.deleteRecord();

gs.info('Deleted Duplicate relationship %% ' + relTypeName + ' between the parent  ' + parent + ' and child ' + child);

}

}

},


/**

  * get a child of this parent of type matched by the descriptor

  *

  * Descriptor is of form <Parent Relationship>::<Child Relationship>

  * so, for example calling this method on a web server with descriptor "RunsOn::Runs"

  * returns the computer it runs on.  Thus, web server is the parent and computer is the child

  */


getChildCI: function(parent, descriptor) {

var gr = new GlideRecord("cmdb_rel_ci");

gr.addQuery("parent", parent.sys_id);

if (descriptor) {

var relationType = this.findCIRelationshipType("cmdb_rel_type", descriptor);

if (relationType)

gr.addQuery("type", relationType);

}

gr.query();


if (gr.next()) {

var cigr = new GlideRecord("cmdb_ci");

if (gr.child && cigr.get('sys_id', gr.child)) {

return cigr;

}

}

return null;

},


    reclassify: function(gr, newClassName, reason) {

        // we are already that class, just return

        if (gr.sys_class_name == newClassName)

            return gr;


        var rci = SncReclassifyCI.createFromGlideRecord(gr, newClassName);

        rci.setApplyDefaults(false);

        rci.setReason(reason);

        return rci.reclassify();

    },


    deleteCIBySysId: function(sysId, workflow) {

        var gr = new GlideRecord("cmdb_ci");

        if (!sysId || !gr.get('sys_id', sysId))

            return;


        this.deleteCI(gr, workflow);

    },


    deleteCI: function(gr, workflow) {

        var al = [];

        al.push(gr.getValue("sys_id"));


        //Check to see if it matches these two criteria

        if (!(gr.instanceOf("cmdb_ci_computer") || gr.instanceOf("cmdb_ci_appl"))) {

            gr.deleteRecord();

            return;

        }


        if (workflow && workflow != "false") {

            this.deleteCIAndRelationshipsRecursive(al);

            return;

        }


        try {

            var oldWorkflow = session.getWorkflow();

            this.deleteCIAndRelationshipsRecursive(al);

        } finally {

            session.setWorkflow(oldWorkflow);

        }


    },


    /*

    * This is where the heavy lifting of traversing through the relationship tree is done

    * We only traverse through the relatinoships that have RUNS_ON and HOSTED_ON relationships at this point

    *

    * We basically look for all the parent CIs that runs on or is hosted on the child CI(s) and delete them.

    */


     deleteCIAndRelationshipsRecursive: function(appList) {

     if (appList.length == 0)

            return appList;


     var appListNew = [];

     var tempSysId;

     var sysID;

         for (var i = 0; i < appList.length; i++) {

             sysID = appList[i];

         var gr = new GlideRecord("cmdb_rel_ci");

         gr.addQuery("child", sysID);

         var qc = gr.addQuery("type", this.findCIRelationshipType("cmdb_rel_type", "Runs on::Runs"));

         qc.addOrCondition("type", this.findCIRelationshipType("cmdb_rel_type", "Hosted on::Hosts"));

         gr.query();

         while (gr.next()) {

         tempSysId = gr.getValue("parent");


         //Check to see if same CI could runs-on or be hosted on same child (maybe possible?)

         if (!contains(appListNew, tempSysId))

            appListNew.push(tempSysId);


                 gr.deleteRecord(); //delete the relationship entry

         }


         var cigr = new GlideRecord("cmdb_ci");

         if (sysID && cigr.get('sys_id', sysID))

        cigr.deleteRecord();

          }


      return this.deleteCIAndRelationshipsRecursive(appListNew);


          function contains(arr, value) {

             for (var i=0; i<arr.length; i++)

               if (arr[i] == value)

                  return true;

             return false;

          }


       },


findOrCreateRelationshipType: function(refTable, descriptor) {

var result = this.findCIRelationshipType(refTable, descriptor);

if (JSUtil.notNil(result))

return result;


var al = descriptor.split("::");

        var gr = new GlideRecord(refTable);

        gr.parent_descriptor = al[0];

        gr.child_descriptor = al[1];

return gr.insert();

},


    findCIRelationshipType: function(refTable, descriptor) {


// refTable should be an optional parameter (because we always pass the

// same value).  I can't change the function signature, so this is the

// only way to make it optional.

if (!descriptor)

return this.findCIRelationshipTypeByDesc('cmdb_rel_type', refTable);


return this.findCIRelationshipTypeByDesc(refTable, descriptor);

    },


    findCIRelationshipTypeByDesc: function(refTable, pDescriptor, cDescriptor) {


var descriptor = pDescriptor;

if (cDescriptor)

descriptor += '::' + cDescriptor;


relTypes[descriptor] = relTypes[descriptor] || getRelType();


return relTypes[descriptor];


function getRelType() {


if (pDescriptor && !cDescriptor) {

pDescriptor = pDescriptor.split('::');

cDescriptor = pDescriptor[1];

pDescriptor = pDescriptor[0];

}


var gr = new GlideRecord(refTable);

gr.addQuery("parent_descriptor", pDescriptor);

gr.addQuery("child_descriptor", cDescriptor);

gr.query();

if (gr.next())

return '' + gr.getValue("sys_id");


return "";

}

    },



    /* Manage the PIDs creation and update */

    insertPIDs: function(pids, app_sys_id, ci_sys_id) {

        if (StringUtil.nil(pids))

            return;


        var pid_array = pids.match(/\d+/g);

        var gr = new GlideRecord("cmdb_pid");

        gr.initialize();

        for (var i=0; i<pid_array.length; i++) {

           gr.pid = pid_array[i];

           gr.application = app_sys_id;

           gr.cmdb_ci = ci_sys_id;

           gr.insert();

        }

    },


    updatePIDs: function(pids, app_sys_id, ci_sys_id) {

        if (StringUtil.nil(pids))

            return;


        var gr = new GlideRecord("cmdb_pid");

        gr.addQuery("application", app_sys_id);

        gr.query();

        gr.deleteMultiple();


        this.insertPIDs(pids, app_sys_id, ci_sys_id);

    },


    /**********************************************

     * Manage the Windows installed software xml

     *

     * Example payload:

     *   <results probe_time="6313">

     *     <result>

     *       <Registry>

     *         <entry key="HKEY_LOCAL_MACHINE">

     *           <entry key="Software">

     *             <entry key="Microsoft">

     *               <entry key="Windows">

     *                 <entry key="Name">

     *                   <value>Just a name</value>

     *                 </entry>

     *               </entry>

     *             </entry>

     *           </entry>

     *         </entry>

     *       </Registry>

     *     </entry>

     *   </results>

     *

     *   // To find the value of the key called "name", here's how these methods can be used.

     *   // registry is a variable representing the payload

     *   var node = findRegistryNode(registry, "HKEY_LOCAL_MACHINE.Software.Microsoft");

     *   var name = findNodeValueWithAttribute(node, "Name");

     *********************************************/

    findRegistryNode: function(currNode, regName){

    var node = currNode;

    var names = regName.split(".");


    for (var i=0; i<names.length; i++) {

        node = this.findNodeWithAttribute(node, names[i]);

            if (!node)

                return null;

        }


    return node;

    },


    findNodeWithAttribute: function(currNode, attrName) {

        if (JSUtil.nil(currNode))

            return "";


        var nodeArray = g_array_util.ensureArray(currNode.entry);

    for (var i=0; i<nodeArray.length; i++)

        if (nodeArray[i]['@key'] == attrName)

            return nodeArray[i];


    return null;

    },


    findNodeValueWithAttribute: function(currNode, attrName) {

        if (JSUtil.nil(currNode))

            return "";


        var nodeArray = g_array_util.ensureArray(currNode.entry);

    for (var i=0; i<nodeArray.length; i++)

        if (nodeArray[i]['@key'] == attrName)

            return nodeArray[i].value;


        return "";

    },


    type: "DiscoveryFunctions"

};


}());


Virtual check BR

 /*

 * Maybe move this to an event on device complete if this ends up being a perforamnce issue.

 *    The reason is this BR would run as long there's data in serial_number or correlation_id.

 */


(function() {

        var g_disco_functions = new DiscoveryFunctions();


        var fVMGr = current;

        var fInstanceGr;

        var fHypervisorGr;

        startVirtualComputerCheck();

        setIsVirtualForCloudIPs();

        // Updated as per  request from CMDB STRY3415899

        function startVirtualComputerCheck() {

            // Putting the easier ones to identify at the front so we don't spend extra effort looking up the others

            if (isSolarisZone())

                handleSolariZone();

            else if (isVMWare()) {

                // only process rec if just inserted or serial_number changed AND serial_number is non-nil

                if (!(JSUtil.notNil(current.serial_number)))

                    return;


                handleVMWare();

            } else if (isHyperV())

                handleHyperV();

            else if (!isCredentialless())

                return;


            current.virtual = true;


            // By this point we know if we have found a vm instance record

            if (JSUtil.nil(fInstanceGr))

                return;


            // We DO have an instance record, so let's create the "instantiates" relationship between VM and Instance

            g_disco_functions.createRelationshipIfNotExists(fVMGr, fInstanceGr, "Instantiates::Instantiated by");


            // Now, let's find the hypervisor...

            fHypervisorGr = findVMWareByImage(fInstanceGr);

            if (JSUtil.nil(fHypervisorGr))

                return;


            // The HyperVisor DOES exist, so let's create the "virtualized by" 'relationship between VM and Hypervisor

            // However, before we do that, let's see if VM already has relationship with another Hypervisor and if so, we

            // need to migrate the relationship. 

            // *note: This shouldn't happen if the relationship was properly managed from the VM instance side. 

            // But we'll do it just in case...

            reconcileRelationVMtoHyperVisor();


        }


        function isSolarisZone() {

            if (fVMGr.sys_class_name != "cmdb_ci_solaris_server")

                return false;


            if (!fVMGr.correlation_id.hasValue())

                return false;


            if (!fVMGr.correlation_id.startsWith("zone-"))

                return false;


            return true;

        }


        function isVMWare() {

            if (!fVMGr.serial_number.hasValue())

                return false;


            if (!fVMGr.serial_number.toLowerCase().startsWith("vmware-"))

                return false;


            return true;

        }


        function isHyperV() {

            var serialNumber = fVMGr.serial_number;

            if (!serialNumber.hasValue())

                return false;


            var instGr = new GlideRecord("cmdb_ci_hyper_v_instance");

            var serials = ['chassis_serial', 'bios_serial', 'baseboard_serial'];

            return serials.some(

                function(serial) {

                    instGr.initialize();

                    if (instGr.get(serial, serialNumber)) {

                        fInstanceGr = instGr;

                        return true;

                    }

                }

            );

        }


        function handleSolariZone() {

            var matchingId = fVMGr.correlation_id.substring(5);


            var gr = new GlideRecord('cmdb_ci_solaris_instance');

            gr.addQuery('correlation_id', matchingId);

            gr.query();

            if (gr.next())

                fInstanceGr = gr;

        }


        function isCredentialless() {

            var potentialVmInstances, potentialGuests;


            // Check to see if this is a record being created by credentialless discovery.  If so we'll attempt to

            // reconcile with a VMWare VM based on IP.  We're limiting the check to VMWare VMs because that limits the

            // risk while solving the associated INT.

            if (!current.ip_address || !current.ip_address.changes() || current.discovery_source != 'CredentiallessDiscovery')

                return;


            potentialVmInstances = new GlideRecord('cmdb_ci_vmware_instance');

            potentialVmInstances.addQuery('ip_address', current.ip_address);

            potentialVmInstances.setLimit(2);

            potentialVmInstances.query();


            // find all potential "other" guests with the IP

            potentialGuests = new GlideRecord('cmdb_ci_computer');

            potentialGuests.addQuery('ip_address', current.ip_address);

            potentialGuests.addQuery('sys_id', '!=', current.sys_id);

            potentialGuests.setLimit(2);

            potentialGuests.query();


            commonVMWareHandling(potentialVmInstances, potentialGuests);


            return !!fInstanceGr;

        }


        function handleVMWare() {

            var serial_number, matchingId, potentialVmInstances, potentialGuests, warnMsg;

            serial_number = fVMGr.serial_number;

            matchingId = fVMGr.serial_number.substring(7);


            // find all potential VM instances with this serial number

            potentialVmInstances = new GlideRecord('cmdb_ci_vmware_instance');

            //potentialVmInstances.addQuery('correlation_id', matchingId);

            potentialVmInstances.addQuery('correlation_id', 'STARTSWITH', matchingId);

            potentialVmInstances.query();


            // find all potential "other" guests with the same serial number

            potentialGuests = new GlideRecord('cmdb_ci_computer');

            potentialGuests.addQuery('serial_number', serial_number);

            potentialGuests.addQuery('sys_id', '!=', fVMGr.sys_id);

            potentialGuests.query();


            commonVMWareHandling(potentialVmInstances, potentialGuests);


            if (!fInstanceGr) {

                warnMsg = gs.getMessage('Unable to uniquely match VMWare instance with guest based on serial number: {0}.\n' +

                    'The correct VMWare instance associated with this guest will be resolved during the next vCenter discovery.', serial_number);

                DiscoveryLogger.warn(warnMsg, "Virtual Computer Check", "");

            }

        }


        function commonVMWareHandling(potentialVmInstances, potentialGuests) {

            var unreconciledVmInstances, unreconciledGuests, unreconciledVmSize, unreconciledGuestSize;


            // if there's only one VM instance, and no other guests

            // save the VM instance and return

            if (potentialVmInstances.getRowCount() == 1 && potentialGuests.getRowCount() == 0) {

                potentialVmInstances.next();

                fInstanceGr = potentialVmInstances;

                return;

            }


            unreconciledGuests = [];

            while (potentialGuests.next()) {

                unreconciledGuests.push(potentialGuests.getValue('sys_id'));

            }


            unreconciledVmInstances = [];

            // Filter out any VM instances & guests that are already reconciled with a relationship.

            while (potentialVmInstances.next()) {

                var vmInstance = potentialVmInstances.getValue('sys_id');

                var isReconciled = JSUtil.getBooleanValue(potentialVmInstances, 'guest_reconciled');


                // if a relationship between this guest and a VM instance already exists then return

                if (isReconciled && g_disco_functions.relationshipExists(fVMGr, vmInstance, "Instantiates::Instantiated by"))

                    return;


                if (isReconciled) {

                    // if the relationship between another guest and this VM instance exists, then don't consider it an unreconciled relationship

                    var relFound = false;

                    for (var i = unreconciledGuests.length - 1; i >= 0; i--) {

                        if (g_disco_functions.relationshipExists(unreconciledGuests[i], vmInstance, "Instantiates::Instantiated by")) {

                            relFound = true;

                            unreconciledGuests.splice(i, 1);

                        }

                    }

                    if (!relFound)

                        unreconciledVmInstances.push(vmInstance);

                } else

                    unreconciledVmInstances.push(vmInstance);

            }


            unreconciledVmSize = unreconciledVmInstances.length;

            unreconciledGuestSize = unreconciledGuests.length;


            // If we have no unreconciled VM instances then return

            if (unreconciledVmSize == 0)

                return;


            // If we have only 1 unreconciled VM instance and no other unreconciled guests

            // save the VM instance and return

            if (unreconciledVmSize == 1 && unreconciledGuestSize == 0) {

                fInstanceGr = unreconciledVmInstances[0];

                return;

            }

        }


        function handleHyperV() {

            matchingId = fVMGr.serial_number + '';

            // The fInstanceGr is already handled in isHyperV() method. Just so that we don't waste another query.

        }


        function findVMWareByImage(instGr) {

            var gr = new GlideRecord("cmdb_rel_ci");

            gr.query("parent", instGr.sys_id);

            gr.query("type", g_disco_functions.findCIRelationshipType("cmdb_rel_type", "Registered on::Has registered"));

            gr.query();

            if (gr.next())

                return gr.child;

            else {

                //There are no Registered on::Has registered relationships for vm instance,

                //i.e vm was migrated and Registered on::Has registered was deleted, deleting the Virtualized by::Virtualizes relationships

                var relGr = new GlideRecord('cmdb_rel_ci');

                relGr.addQuery("parent", fVMGr.sys_id);

                relGr.addQuery("type", g_disco_functions.findCIRelationshipType("cmdb_rel_type", "Virtualized by::Virtualizes"));

                relGr.query();

                if (relGr.next())

                    relGr.deleteMultiple();

            }


            return;

        }


        function reconcileRelationVMtoHyperVisor() {

            var gr = new GlideRecord('cmdb_rel_ci');

            gr.query('parent', fVMGr.sys_id);

            gr.query('type', g_disco_functions.findCIRelationshipType("cmdb_rel_type", "Virtualized by::Virtualizes"));

            gr.query();


            // If we found nothing, then let's simply create the relationship between VM and Hypervisor

            if (gr.getRowCount() == 0) {

                g_disco_functions.createRelationshipIfNotExists(fVMGr, fHypervisorGr, "Virtualized by::Virtualizes");

                return;

            }


            // We found existng relationship(s) between VM and HyperVisor(s). Theoretically there should be only 1

            // If we did find multiple, then We want to just correct the first relationship and then delete the rest

            var done = false;

            while (gr.next()) {

                if (done == true) {

                    gr.deleteRecord();

                    continue;

                }


                // If they don't match, let's re-point the child to the correct hypervisor

                if ((gr.child.sys_id + '') !== (fHypervisorGr.sys_id + '')) {

                    gr.child = fHypervisorGr.sys_id;

                    gr.update();

                } // The other possibliy is that the sys_id matches, in which case there would be nothing to do 


                done = true;

            }

        }


        function setIsVirtualForCloudIPs() {

            var IP = current.ip_address.toString();

            if (IP.startsWith('10.245') || IP.startsWith('10.247') || IP.startsWith('10.248') || IP.startsWith('10.249'))

                current.virtual = true;

        }

    }


)();




Monday, December 3, 2018

Discovery Errors with Resolution and Explanation

How to capture the Inbound REST logs and the associated REST Request Body in the Service Now system logs.

Steps to Debug Inbound REST API Calls in Service Now:



1.    Make sure the property “glide.rest.debug” is set to true under sys_properties table.




2. Get the REST request URL and the user_id of the user with which the REST call is coming to instance.

REST Request URL à https://******.service-now.com/api/now/table/incident

userid à  mychartintegration

3. Log onto instance and navigate to the Transactions under System Logs.
Search for the user_id in created by field and REST request URL in URL field (eg. for REST URL - https://nychhcdev.service-now.com/api/now/table/incident look for "/api/now/table/incident" in the URL field of transaction logs)


4.  Note the Ticket created time for which ticket  you are facing issue and open that particular transaction log from transactions above.
Ticket created à 12/04/2018 11:07:25



5. Find the transaction from above and note the value in System ID (node name) and Session ID fields of the identified transaction.
If you don’t find system ID, configure Form layout and add the field on the form.

System id à *************************
Session ID à *************************

6.    Navigate to the stats page to find the node you are logged in. (Check 2nd line on the page which says - Connected to cluster node and note the node name) https://nychhcdev.service-now.com/stats.do

Cluster node à *****************************

7. If Cluster node and System ID are same from 5 and 6 steps above:
n   Then, it’s easy to debug.
n  Open Node Log File Browser under System Logs and copy Session ID and Change Start time and End time to ticket creation time approximately.
n  You will see the Incoming Request Body  here with the clear incoming request.




8.  If Cluster node and System ID are different from 5 and 6 steps above:
n  Then, Go to Node Log File Download under System Logs and download localhost log for the day when the request was made to the instance.


9) Once you download the correct logs from STEP 8, open with Windows Wordpad Application and do a "search" on the log file using the Session ID identified in Step 5.

10) The Session logs which will be obtained from the filtered logs in step 9 will have the Request body in the logs which is sent to ServiceNow.


Discovery troubleshooting | Error messages

  Discovery troubleshooting | Error messages - Support and Troubleshooting (servicenow.com) Description Learn how to resolve common Discover...