kevinray
Giga Expert

I was asked by my company to integrate Quest Foglight to Servicenow. REST with Foglight is a new function for them with their latest release, so there wasn't much knowledge about it. After hours upon hours upon hours of research and coding, I finally got it all to work! I am by no means a ServiceNow expert, nor am I Web Services expert. This was part of the issue I suppose. lol. I didn't want anyone else to go through the pain, so I wanted to document what the requirements were and how we did it.

Much of the struggle was initially on the Foglight side. Even though they were on a version that had REST, there were bugs and we couldn't ever get it to connect. Once they upgraded some things that seemed to help things. Please work with your Quest Foglight admin and try to get on the latest Foglight release to save yourself frustration and time. That last struggle I had was that I couldn't seem to get the JSON parsing to work (which we will talk about later). This was ultimately my fault because I didn't understand the Name:Value pair I was trying to get was a inside of another object (NV pair within a NV pair). Once I figured that out, it was easy. Again, hours of time only because I didn't truly understand the structure of the data that I was getting back from Foglight. It wasn't until I put the data in to a JSON Formatter (which you can do online for free) that I realized what was happening. (Lesson learned) I just to try and save other some time if possible so here ya go.

OUR REQUIREMENTS

  • Create an inbound REST endpoint in to ServiceNow so that Foglight can create incidents from it's alarms and upon confirmation, get the ticket number and the group the ticket was assigned to, back. (we have support groups linked to our services. When a ticket is opened, the system checks what support group supports the identified service, and auto assigns the ticket to that group)
  • Create an outbound REST call to Foglight that will clear the alarm out of Foglight when the incident is resolved.

IMPORTANT CONSIDERATIONS

  • Foglights design utilizes many servers across the infrastructure to be the 'hosts' (for lack of a more knowledgeable term) that capture and 'holds' the alerts. As such, clearing the alarm cannot be sent to one server. You have to send the clear call to the server that is hosting the alarm (this can vary).   The format for this REST call is:
    • http://<server>:<port>/api/v1/alarm/clear/<alarmID>
  • This means I needed to capture the server:port and alarmID in the Incident so that I knew where to send the clear call to once the Incident was resolved.

THE DESIGN and SOLUTION

Step 1: Create the fields on the Incident record

First things first…CREATE AN UPDATE SET AND MAKE IT CURRENT!

We already had a "reference" field on our Incident screen that people could use for anything they want related to their incident that was 40 characters long. The Alarm ID is always 40 characters so I decided to just use that. "Reference" (u_reference). You might need to create a new field. Up to you, what you have and what you need. Just needs to be a string at LEAST 40 characters in length.

I now needed a field that would store the server and port information, so I just created a field on my Incident record called "Foglight Alert Server" (u_foglight_alert_server). I kept it hidden because it adds no value seeing it and just clutters up the page.

Step 2: Create the Foglight Integration Account

Our standards in my company are to always include the word "Integration" in the naming convention of our integration user accounts. Additionally, we have a group called "API Service Accounts" with the proper roles linked so any account assigned to that group gets the proper roles. (It's also real easy to find all your API accounts if you do it this way) All SOAP and REST accounts are linked to this group in our company. The roles assigned are:

  • Soap
  • Rest_service
  • Import_transformer
  • Import_set_loader

You may not want to give your API accounts import roles, so at a minimum ensure it's given the REST_SERVICE role. Again, depends on your needs.

Step 3: Provide the Foglight adminisrator the credentials, the endpoint and the fields they need to pass to create the incident

This is where the ServiceNOW "REST API Explorer" comes in REAL handy. I wont explain how you use it here as it's very easy to use and there is a lot of documentation on it, but you have a lot of options to determine what endpoint you need them to use.

Here was mine:

https://xxxxx.service-now.com/api/now/table/incident?sysparm_display_value=true&sysparm_exclude_refe...

Let's break it down

  • https://xxxxx.service-now.com/api/now/table : standard ServiceNow api access were xxxx is your instance
  • /incident? : this is the table that you want to create a record on
  • sysparm_display_value=true : If your going to return a reference field (like a group) you don't want to return the SYSID because that isn't helpful. You want to return the actual group name
  • &sysparm_exclude_reference_link=true : if you don't set this to true and you are returning a reference field (like a group), instead of just the group name, you get a link to that actual record. We don't want that.
  • &sysparm_fields=number%2Cassignment_group : this is a comma separated list of incident fields you want to return to Foglight once the Incident has been created. (%2C = a comma)

Required Fields that Foglight needs to include with their REST call to ServiceNOW:

Every process is different, but for us, these are the fields that are required in order to open an incident. Some let let them select what they want, some (like category) we tell them what to set it at. REMEMBER: we need to extra fields for this integration (alertID and server) so be sure to get them.

u_technical_service = [name of application experiencing the alert] *REQUIRED
cmdb_ci = [name of server experiencing the alert} — optional
short_description [short description of issue/ alert] *REQUIRED
description = [full description of issue. Include all details] *REQUIRED
impact = [choices are 1 — High, 2 — Medium, 3 — Low ] *REQUIRED
urgency = [choices are 1 — High, 2 — Medium, 3 — Low ] *REQUIRED
category = Software *REQUIRED
subcategory = [choices are File, Installation, Reported Bug, Error, Performance, Configuration, Connectivity, Information] *REQUIRED
u_referance = [Foglight alert number/reference] *REQUIRED
u_foglight_alert_server = [in this format please] http://<servername>:<port>/ (example: http://server123.com:8443/) *REQUIRED

Step 4: Create your REST endpoint to Foglight

While we are using "basic authentication" for this REST Call (ID and PW) interestingly, the Foglight integration will not let you call the "GET" CLEAR ALARM call using basic authentication method alone. You first have to use basic authentication to get a token using a "POST" LOGIN call, then take the token you get back and pass that + the ID + the PW   to the "GET" CLEAR ALARM call to clear the alarm. We are going to first create our Outbound REST endpoints, then we are going to use a business rule to make the actual calls happen so that we can easily get the token, and pass that variable onward.

First things first…

  • Create a NEW Outbound REST record
    • Name: Foglight Integration
    • Description: Used to close foglight alerts when associated incident is moved to resolved.
    • Endpoint: ${serverhost}api/v1/alarm/clear/${alarmID} (If you don't see this field, you might have to edit your form to add it)
    • Authentication type: None

You should now have something that resembles this:

find_real_file.png

Click in to the "post" method to configure it

We need to change the endpoint for the post because this is what Foglight needs to log in and get the token. The format for the post login is http://<servername>:<port>/api/v1/security/login. Because we are going to use the field from our incident to determine what the servername and port is, we need to keep that set as a variable but edit the rest so it looks like this: ${serverhost}api/v1/security/login

  • Click the 'lock' icon to the right of the endpoint field so you can edit it
  • Change the Endpoint to: ${serverhost}api/v1/security/login

find_real_file.png

Go to the HTTP Request tab.

Set the MID server to one of your MID servers. This is the 'bridge' that allows you to authenticate within your infrastructure seeing that ServiceNOW is in the cloud.

Create an HTTP Header.

  • Name: Content-type, Value: application/x-www-form-urlencoded

In the HTTP Query Parameters table create three rows

  1. Name: username, Value: [the Username of the Foglight account]
  2. Name: pwd, Value: [the password of the Foglight account]
  3. Name: serverhost, Value: leave blank (we are going to pass this variable when we call this)

You should now have something that resembles like this:

find_real_file.png

Go back to your main Outbound REST screen and Click in to the "get" method to configure it

Go to the HTTP Request tab

Set the MID server to one of your MID servers. This is the 'bridge' that allows you to authenticate within your infrastructure seeing that ServiceNOW is in the cloud.

Create two HTTP Headers.

  • Name: Accept, Value: application/json
  • Name: Auth-Token, Value: ${token} (we are going to pass this variable when we trigger this call)

You should have something that looks like this

find_real_file.png

You should now be able to test it by clicking the 'test' link on the POST record If all is well, you should get a json string in the response field that looks something like this:

{"status":1,"data":{"user":{"id":"8e94015b-8ec0-46d6-aff3-c098dbfd77f5","lastLogonTS":1504213765964,"name":"foglight_srvnow","groups":["Foglight Users"],"roles":["API Access","Anybody"]},"token":"s898eectvm3c0kemjhtheb7v09"}}

  • Copy the token value that is returned and put in a notepad or something
  • Click the "Preview Script Usage" link under "related links" and copy the results (we will use it later). It will look something like this
try { 
var r = new sn_ws.RESTMessageV2('Foglight Integration', 'post');
r.setStringParameter('serverhost', 'https://xxxxxxxxxxxxxxxxx:8443/');

//override authentication profile
//authentication type ='basic'/ 'oauth2'
//r.setAuthentication(authentication type, profile name);
var response = r.execute();
var responseBody = response.getBody();
var httpStatus = response.getStatusCode();
}
catch(ex) {
var message = ex.getMessage();
}

The only reason you see the "StringParameter" lines is because we created a "Variable Substitution" record previously. If you didn't do that, they won't show up, and that's ok. You're going to change this code a bit later when we use it.

If you don't get anything back or get an error, you need to check your credentials and work with your Foglight admin to see why your not authenticating.

Your now ready to test the GET CLEAR ALARM call

  • Have your Foglight Admin create an alarm or have him give you an ALARMID and the SERVER on which the alarm is sitting.
  • Create 3 variable substitution record on the GET method as demonstrated below:

find_real_file.png

  • AlarmID and serverhost you need to get from the Foglight Admin
  • Token will be the token you got a minute ago from the POST test.
  • Click Test
  • You should get a Response that looks like this:
    • {"status":1,"data":"success"}
  • Have your Foglight Admin confirm the alert is cleared.
  • Click the "Preview Script Usage" link under "related links" and copy the results (we will use it later). It will look something like this
try { 
 var r = new sn_ws.RESTMessageV2('Foglight Integration', 'get');
r.setStringParameter('alarmID', '94aa0254-e2ef-47d4-9ce3-969850e23386');
r.setStringParameter('serverhost', 'https://xxxxxxxxxxxxxxxxx.com:8443/');
r.setStringParameter('token', 's898eectvm3c0kemjhtheb7v09');
//override authentication profile 
//authentication type ='basic'/ 'oauth2'
//r.setAuthentication(authentication type, profile name);
var response = r.execute();
var responseBody = response.getBody();
var httpStatus = response.getStatusCode();
}
catch(ex) {
var message = ex.getMessage();
}

The only reason you see the "StringParameter" lines is because we created "Variable Substitution" records. If you didn't do that, they won't show up, and that's ok. You're going to change this code a bit later when we use it.

Your Outbound REST record should now look like this:

find_real_file.png

Step 5: Create our Business Rules to make all this work!

BUSINESS RULE #1 — Set support group (This may or may not be applicable to your integration)

Remember, we want to return the name of the group that is assigned the incident once the rest call is sent to us. Because these are being created via an API, our auto assign rules don't kick in. In order to do that, we need to force the system to set the group upon creation when our Foglight Integration creates an incident.

  • Create new Business Rule
  • Name: Assign incident for Foglight Integration
  • Table: Incident
  • Active: true
    • "When to Run" tab
      • Insert: true
      • Update: false
        • Filter Conditions
          • "Requested By" "is" "whatever the name of the user you created is"
    • "Actions" tab
      • "Assignment group" "Same as" "Technical service.Support Group"
      • NOTE: This is very specific to our company, this our requirements for this integration, and how we built Incident and the requirement. Remember, we wanted to assign the incident to whatever support group is on the Technical Service record that is being indicated. Clearly if you don't use "technical services" and you don't use "support group" field on them, then this won't work for you. This is just to demonstrate how I am auto assigning REST created Incidents from Foglight.
  • SAVE

BUSINESS RULE #2 — run REST call to trigger clear alarm

Because we have to run a POST to get a token, then run a GET to clear the alarm, I created a business rule to trigger all this when Incidents that were created by Foglight are moved in to a Resolved State.

  • Create new Business Rule
  • Name: Clear Foglight Alert
  • Table: Incident
  • Active: true
  • Advanced: true
    • "When to Run" tab
      • When: after
        • Unfortunately, Asynchronous business rules do not have access to the previous version of a record. Therefore, the changes(), changesTo(), and changesFrom() GlideElement methods don't work. This is unfortunate because this will slow down user experience of the closure of the incident by a few seconds (while the Web Services get the token, and clear the alarm the screen will not change until this is all done) but it is what it is. I'm sure there is another way to accomplish this, but at the time of this writing I don't know how else to do it.
      • Update: TRUE
      • Insert, Delete & Query: FALSE
      • Filter Conditions (Set these based on your needs and Foglight user name)
        • State Changes To Resolved
        • Reopen Count is 0
        • Opened By is Foglight Integration
    • "Advanced" tab
      • Now, we are going to paste our POST script first and edit it so that we not only make sure we populate the serverhost variable, but that we parse out our token when we get it back. Paste your POST code and edit it like this:
try {
var r = new sn_ws.RESTMessageV2('Foglight Integration', 'post');
var serverName = current.u_foglight_alert_server; //this get's the alert server name
r.setStringParameter('serverhost', serverName); // use the variable not the hardcoded test variable
var response = r.execute();
var responseBody = response.getBody();
var httpStatus = response.getStatusCode();
var parsed = JSON.parse(responseBody); //we need to parse out the token.
var authCode = parsed.data.token; // It is within the 'data' object so we need to indicate that
}
catch(ex) {
                var message = ex.getMessage()
}
  • Now we are going to paste our GET script that we copied earlier. We are going to need to modify it to account for our variables and such…it will look like this
try {
var r = new sn_ws.RESTMessageV2('Foglight Integration', 'get');
var alarm = current.u_reference; //get the alarm ID from the incident
r.setStringParameter('alarmID', alarm); //set this to a variable instead of hard coded
r.setStringParameter('serverhost', serverName); //set this to a variable instead of hard coded
r.setStringParameter('token', authCode);//get the token from the POST above
var response = r.execute();
var responseBody = response.getBody();
var httpStatus = response.getStatusCode();
}
catch(ex) {
  var message = ex.getMessage();
}
  • Now I want to write to the incident what we did (optional). Looks like this
current.work_notes ='Sent clear request to Foglight for server: '+ serverName + ' & Alarm ID: ' + alarm ;
current.update();

So your full business rule will look like this:

try {
var r = new sn_ws.RESTMessageV2('Foglight Integration', 'post');
var serverName = current.u_foglight_alert_server; //this get's the alert server name
r.setStringParameter('serverhost', serverName); // use the variable not the hardcoded test variable
var response = r.execute();
var responseBody = response.getBody();
var httpStatus = response.getStatusCode();
var parsed = JSON.parse(responseBody); //we need to parse out the token.
var authCode = parsed.data.token; // It is within the 'data' object so we need to indicate that
}
catch(ex) {
                var message = ex.getMessage()
}

try {
var r = new sn_ws.RESTMessageV2('Foglight Integration', 'get');
var alarm = current.u_reference; //get the alarm ID from the incident
r.setStringParameter('alarmID', alarm); //set this to a variable instead of hard coded
r.setStringParameter('serverhost', serverName); //set this to a variable instead of hard coded
r.setStringParameter('token', authCode);//get the token from the POST above
var response = r.execute();
var responseBody = response.getBody();
var httpStatus = response.getStatusCode();
}
catch(ex) {
  var message = ex.getMessage();
}
current.work_notes ='Sent clear request to Foglight for server: '+ serverName + ' & Alarm ID: ' + alarm ;
current.update();
  • SAVE

That should be it!

Hope this saves you hours and hours of struggle.

Comments
ayush_saxena
Tera Expert

Nice Information Kevin,

Not sure what was the need to create an Outbound to Foglight to cleat alerts, as it keeps monitoring the servers/services. If the issue is resolved the alert clears itself in our case.

 

My primary question is more around where to consume Servicenow API in foglight. We are on Foglight v5.9.4 and are not able to find a way to consume webservices.

kevinray
Giga Expert

Hello Ayush,

I'm not a FogLight admin or developer so I unfortunately can not answer your question. I built this integration in my previous company, and worked closely with the Foglight administrator...that person set up Foglight.

I would suggest you contact your FogLight support team to get that information. I do recall the FogLight admin having a bit of trouble setting it up, but once he reached out to the FogLight account manager/support team for help, they were able to get it set up.

 

 P.S. I found this: https://www.quest.com/community/quest/performance-monitoring/b/performance-monitoring-blog/posts/foglight-rest-apis-introduction---java-and-python-sample-code-1237861345

Not sure if it helps, but looks like you have to install some sort of "cartridge". Again, I would encourage you to get help from Quest.

Version history
Last update:
‎09-01-2017 11:05 AM
Updated by: