Join the #BuildWithBuildAgent Challenge! Get recognized, earn exclusive swag, and inspire the ServiceNow Community with what you can build using Build Agent.  Join the Challenge.

richardbrounste
ServiceNow Employee
ServiceNow Employee

Introduction

 

ServiceNow Agent-less Discovery is a powerful tool that scans devices in the data center to update the CMDB with thousands of pieces of accurate inventory information.  It uses credentials (userid/password or private key) for authentication to access the devices and collect information on hardware and software applications and populate the CMDB.  These credentials are stored on the ServiceNow instance (or in a local credential vault).

Users of Discovery can supply a set of credentials for each protocol (type of device).  For example, if a user provides a set of 5 different SSH (Unix/Linux) userid/password combinations, then during the discovery process, Discovery will go through each credential in order until one of the userid/password login combinations work.  Once it finds a credential that works, it uses that credential for that IP address for the full discovery and in future discoveries as long as it works.  It can do this because each SSH call will return a pass or fail.  If it fails, Discovery automatically goes back to the credential table and searches for a new credential until it finds one that works.

This sequential mechanism works well for OS credentials and some API mechanisms such as Cloud Discovery.  It does not work the same for Applicative Credentials.

 

richardbrounste_0-1764173685391.png

 

Applicative Credentials

 

Applicative Credentials are a special kind of credential.  They are a generic userid/password combination that pass the userid and password to some command line or an API call.  Discovery doesn’t evaluate if the command or API call passed or failed.  It only knows that it is providing the credential to some command and has no way of knowing if the command result worked or not.  Thus, it doesn’t know if the credential failed and won’t know to try the next credential on the list.  This limits users to only one possible applicative credential for each CI type.  The purpose of this article is to describe a way that users can supply a set of applicative credentials that can be tested until one passes, or to allow a discovery pattern to select a specific credential.

 

richardbrounste_1-1764173761614.png

Credential processing for applicative credentials.  It will only select the first credential.

 

SELECT AN APPLICATIVE CREDENTIAL BASED ON A PARAMETER

There is a way in a ServiceNow Discovery pattern to select a specific applicative credential.  Using some Java Script code in an “Eval” statement in a pattern step, the code can parse through all the applicative credentials for a specific CI type and select the one we want based on the username of that credential or keep trying a command until the command no longer fails.

To do this, we will invoke a function called: “getApplicativeCredentials” that is called from the CTX global object.  Here is the syntax that returns an array of Applicative credentials.  In my example, I have 2 Applicative Credentials defined in the credential table of the CI Class type: “sn_itom_pattern_cmdb_ci_servicenow_platform”.

richardbrounste_2-1764173846640.png

The following lines of JavaScript code will retrieve these credentials in an array and puts the user name into a variable called ‘user’ and the password into a variable called ‘pass’ as it parses through the array:

var ciType = 'sn_itom_pattern_cmdb_ci_servicenow_platform';
var credList = CTX.getApplicativeCredentials(ciType).iterator();
while(credList.hasNext())
  {
  creds = credList.next();
  var user = creds.getUserName();
  var pass = creds.getPassword();
  }

 

I can put this code into a Discovery pattern step that sends an HTTP REST API call from the MID Server to a server.  In this example, I’m using ServiceNow’s REST API, where I can query data from a ServiceNow instance table.  In ServiceNow, I can send an HTTP REST API request to query a list of all the Linux Servers using the following URL:

 

https://<instance_name>.service-now.com/api/now/table/cmdb_ci_linux_server?sysparm_query=serial_numberISNOTEMPTY&sysparm_fields=name'

 

This URL call will return a List of entries from the Linux Server (cmdb_ci_linux_server) table where the serial_number is not empty and will return the name column.  It requires a header encoded with the userid/password of a user with read access to this ServiceNow instance.  That can be done with the following code:

 

basicAuthHeader = "Authorization: Basic " + base64.encodeBase64String(ioutils.toByteArray(user_pass));

the “user_pass” variable must have the userid and password in the format: “<username>:<password>”.

 

Here is the final code that we can put into an eval statement in a “Set Parameter Value” operation in a discovery pattern.  The code assumes that we have a variable called “url”. This is the URL of the ServiceNow instance:

 

richardbrounste_3-1764174013544.png

 

richardbrounste_4-1764174044422.png

 

var HTTPRequest = Packages.com.glide.communications.HTTPRequest;
this.httpCall = Packages.com.snc.sw.commands.HttpCallHandler;
var base64 = new Packages.org.apache.commons.codec.binary.Base64();
var ioutils = new Packages.org.apache.commons.io.IOUtils();
var httpClient = new this.httpCall();
var ciType = 'sn_itom_pattern_cmdb_ci_servicenow_platform';
var credList = CTX.getApplicativeCredentials(ciType).iterator();
var url=${InstanceURL};
var rtrn='';  /* initialize the return variable */
while(credList.hasNext())
  {
  creds = credList.next();
  var user = creds.getUserName();
  var pass = creds.getPassword();
  var user_pass = user + ':' + pass;
  basicAuthHeader = "Authorization: Basic "  + base64.encodeBase64String(ioutils.toByteArray(user_pass));
  headers = "Authorization: " + "Basic " + user_pass;
  url += '/api/now/table/cmdb_ci_linux_server?sysparm_query=serial_numberISNOTEMPTY&sysparm_fields=name';
  var response  = httpClient.invoke(CTX,url,'GET',null,null,ciType,basicAuthHeader,'false');
  if (response.indexOf ( 'User is not authenticated') == -1)
    {
    rtrn = response;
    break;
    }
  }

 

 

CONCLUSION

 

We now have a solution that will send in an applicative credential and will keep trying all the applicative credentials of a particular CI Type until it finds one that works.  The example used a REST API call.  A similar solution could work with a command line.  There are many ways to use Javascript to do advanced operations in a discovery pattern.  You would just substitute the “httpClient.invoke” function call with code like the following:

 

cmd = "myutility -user " + user + " -password " + password;
response = CTX.getCommandManager().shellCommand(cmd, false, null, null, CTX);
if (response.indexOf ( 'invalid user or password') == -1)
  rtrn = response;

 

Happy Pattern Building!