Tuesday, February 27, 2024

Discovery troubleshooting | Error messages

 Discovery troubleshooting | Error messages - Support and Troubleshooting (servicenow.com)


Description

Learn how to resolve common Discovery error messages with the information below. 

Discovery general messages

Message: org.xml.sax.SAXParseException: The entity name must immediately follow the '&' in the entity reference

A version of this message occurs if you have used special characters in a password that is saved in an XML file. More information

Message: Identified, ignored extra IP

This message can appear during the identification phase of Discovery if a targeted IP address belongs to a device that is being discovered at the same time.
Example: A Windows server has two NIC cards with two IP addresses. Discovery targets both IP addresses within the same Discovery schedule. This message is generated to note that that second IP address is ignored because we don't want to update the same CI twice within the same Discovery run.
This message is a warning and is expected. No action is needed.

Message: Authentication failures

The discovery process could not discover the CI because the discovery application could not authenticate. To resolve, add the credentials of that machine in to the discovery credentials table.

Message: Identified, not updating CI, now finished

No match on any of the CI Identifiers

Message: The impersonation of user failed

This message originates in Powershell. Check that the domain is specified along with the user name in the credentials.

Message: Connection failed to WMI service. Error: Permission denied

This message originates in WMI. Check that the MIS Server service is running with the correct credentials and has access to the target device.
To check this, run the following command from the command prompt on the MID server host:
wmic /node:target /user:user /password:password path win32_operatingsystem
target = IP address of target device
user = user account used by the mid server service
password = password used by the mid server service

Message: Connection failed to WMI service. Error: The remote server machine does not exist or is unavailable

This message originates in WMI. Check that the MID Server service account has access to the targeted machine. Check if a domain admin account is used as the MID server service account? Check if any existing firewalls are open to the connection.
To check this, run the following command from the command prompt on the MIS Server host.
Execute for runner_type=WMI:
wmic /node:"<target>" /user:"<user>" /password:"<password>" path win32_operatingsystem
From within a Powershell console on the mid server host, execute for runner_type=Powershell:
gwmi win32_operatingsystem -computer <ip> -credential '<username>'

Message: Provider is not capable of the attempted operation

WMI repository was corrupted. After following the article below, the problem was corrected.
Ref.: http://blogs.technet.com/b/askperf/archive/2009/04/13/wmi-rebuilding-the-wmi-repository.aspx

Message: The result file can't be fetched because it doesn't exist

Powershell does not work when customer has locked down write rights to admin share. Admin share is always required.
Ref.: https://docs.servicenow.com/csh?topicname=r_AdditionalPermissions.html&version=latest

Message: Please run sneep as root to ensure correct serial number from fserial data source

The Oracle Sneep command line tool must be installed for the Solaris - Serial Number probe to work correctly. There is a [known limitation] with Fujitsu PRIMEPOWER devices. To work around this limitation, run the Solaris discovery with root credentials.

Discovery sensor messages

Message: The multisensor will not process because its major version = X while probe_name responding script's major version = Y
Message: The multisensor will not process because its responding script's major version = X while its referenced probe probe_name major version = Y
Message: sensor_name sensor's major version = X while its related probe's major version = Y


The above error messages indicate that there is a major version mismatch in the probe and sensor versions and the sensor will stop processing until this condition is resolved. More Information

Message: sensor_name multisensor's minor version = X while probe_name responding script's minor version = Y
Message: sensor_name multisensor's responding script's minor version = X while its referenced probe probe_name minor version = Y
Message: sensor_name sensor's minor version = X while its related probe's minor version = Y


The above error messages indicate that there is a minor version mismatch in the probe and sensor versions. Processing will continue, but you may want to resolve this condition. More Information

Message: Sensor error when processing . . .  : No sensors defined


Every active probe looks for a corresponding sensor to process the data that is collected by the probe. The No sensors defined message indicates that the corresponding sensor for the probe is missing or inactive. More information

Message: Sensor error when processing . . . : typeError: . . .

This type error message occurs to indicate the sensor has one of the core error constructors in JavaScript. More Information

Discovery Oracle database instance messages Unix

Message: No Oracle SID was provided

Denotes that the process classification script failed to pass the SID value, or it passed an empty value to the probe’s script. Process classification parses the SID value from the running process that has a name that starts with ora_pmon_.

Message: No Oracle oratab file found

Denotes that discovery could not find oratab file from one of the below location in the given order.
  • /var/opt/oracle/oratab
  • /etc/oratab
  • /var/opt/unix/oratab
  • /etc/oracle/oratab
  • /etc/opt/oracle/oratab
  • /shared/opt/oracle/oratab

Message: Could not read Oracle (s)pfile: pfile

The command to read the spfile on the target machine failed.

Message: No Oracle (s)pfile found (or insufficient permissions)

Check that you have the correct permissions for Discovery to access the Oracle system parameter file.

Message: Could not determine Oracle instance version

Denotes a failed attempt to extract the Oracle version information using the following methods:
  • From the output of the ORA_HOME/bin/sqlplus /NOLOG command
  • From the output of the ORA_HOME/bin/lsnrctl status command
  • From the path of ORA_HOME

Windows

Message: Value for SID is empty. Invocation of Probe 'WMIRunner-Oracle - Instance PFile' is skipped.

To identify the SID value, the probe parses the parameters that are passed to the oracle.exe process. This message can occur if the oracle.exe process is started manually without a SID value as a parameter. This error displays as a warning in the Discovery Log.

Message: Invalid value of oracle exe path: path

Denotes that the process classification script failed to pass the full path of oracle.exe, or it passed an empty value to the probe's PowerShell script.

Message: Invalid value of SID:<<$sid>>

Denotes that the process classification script failed to pass the SID value, or it passed an empty value to the probe's PowerShell script.

Message: Could not able to find the Server Parameter (spfile) file

Specific locations are searched for the spfile. This error occurs if the spfile is at a different location.

Message: Oracle exe path is invalid

Denotes that the process classification script failed to pass the full path of oracle.exe, or it passed an empty value to the probe's PowerShell script.

Message: Could not determine Oracle instance version

To determine the Oracle instance version, the command sqlplus.exe -V is sent to the target machine. This error occurs when the command fails to return a result.

Message: Could not determine oracle instance version from result: result

To determine the Oracle instance version, the command sqlplus.exe -V is sent to the target machine. This error occurs when the command returns a result, but Discovery can not parse the version information from it.

Discovery Mid Server agent log messages Message: WARNING *** WARNING *** A private key has invalid format

The entire contents of the private key needs to be copied in the SSH private key including the---BEGIN and END--- markers.

vCenter Discovery messages

Message: Unable to establish connection to https://10.249.17.207/sdk

  • No VMWare type credential is stored in the credential table.
  • The username is a domain account and needs to be prefixed with a domain.

Message: CIM_RegisteredProfile{{RegisteredName='Base Server'}}.CIM_ElementConformsToProfile{{ResultClass:'CIM_ComputerSystem'}}.CIM_ComputerSystemPackage{{ResultClass:'CIM_Chassis',PackageType='3'}}.* - CIM_RegisteredProfile - Authentication failed.

No CIM type credential is stored in the credential table. Provide the root user with this access.

Message:com.vmware.vim25.NoPermission errors

Provide a credential of type=VMware within the Credentials table.
If the user is part of the domain, it needs to be explicitly defined by username=domain\user.
Within ecc_agent_jar "vijava.jar" there needs to be an attached and readable (downloadable) jar file. The MID server needs to be able to download this jar file.
See also: this article to for information about no using the root account credentials to do CIM queries on ESX.

MSSQL Message: Cannot find type [Microsoft.SqlServer.Management.Smo.Server]: make sure the assembly containing this type is loaded

Install Microsoft SQL Server management library (SMO). More Information

Message: java.sql.SQLException: com.microsoft.sqlserver.jdbc.SQLServerException: SQL Server version 8 is not supported by this driver

Microsoft discontinued support for SQL Server 2000 (8.0) in JDBC version 4, in exchange for native support for SQL Server 2012. More information
Use JDBC version 3, which lacks native support for 2012, but still has support for 2000. More Information

WWI: Get IIS information Message: Invalid namespace

  • The namespace root\MicrosoftIISv2 was replaced by root\WebAdministatration starting with IIS 7.0 (Windows Server 2008)
  • To see which namespaces are available on a machine, type the following command from the Powershell command line:
Get-WMIObject -class __Namespace -namespace root | Format-Table name
Workaround: Install IIS 6 WMI Compatibility server roles for root\MicrosoftIISv2 namespace to be present on Windows Server.

 


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;

        }

    }


)();




Discovery troubleshooting | Error messages

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