May 182015
 

One of my current projects at work is to build up Zabbix as an alerting solution.
This includes using Zabbix to raise incidents in ServiceNow for any alerts that come through.

Initially, I thought that I would need to do lots of scripting, but it turns out I only had to write a simple script to allow Zabbix to raise incidents in ServiceNow.
This was largely thanks to pre-built Python modules that the community have built to allow easy integrations, namely ZabbixAPI and Python-Servicenow.

These 2 libraries made integration easy because they allowed me to concentrate more on the code to join the 2 systems rather than having to figure out how to make them talk to Python, and then talk to each other.

The integration itself will take an alert that is generated by Zabbix and insert the data into ServiceNow as an incident.

Configuring Zabbix

  1. Copy the snippet at the bottom of this post into a file in /usr/lib/zabbix/alertscripts. I’ve named mine servicenowapi.py.
  2. Create a new Media Type.
    Create a new media type by going to Administration => Media types, and click on Create media type.
    Give the Media Type a name, select Script for the Type, and put in the name of the file. Using my example, it would be servicenowapi.py
  3. Assign the new Media Type to a user.
    The user’s “Send to” for the media type will define the assignment group in ServiceNow.
    Click on Administration => Users, select Users in the drop down on the top right, and click on a user. Once you’re in the user’s configuration page, click on the Media tab, and then click on ‘Add’.
    Select the new Media Type from the type drop down, and then enter in the ServiceNow Assignment Group in the ‘Send To’ box, and click ‘Add’.
  4. Create or modify an existing action to start sending incidents to ServiceNow.
    Click on Configuration => Actions, and open up an Action. Click on the Operations Tab, and click on “New”.
    Click on “Add” in the Send To Users section, and choose the user that has the ServiceNow Media type set up.
    Select the ServiceNow action in the “Send only to” box, and then click on the “Add” button to add the action to the list of actions.
    Once the action has been setup, click on Save.

Once the alert is all set up, whenever the alert is triggered, the script should log an incident directly into ServiceNow.

servicenowapi.py

The below code should be copied and pasted into a file to be used as the script for the Media Type.

#!/usr/bin/python
import zapi
import datetime
import sys
import urllib2
import os
import servicenow.Connection
import servicenow.ServiceNow

##
## I've used logging for my own setup, but I've commented it out so that it won't spam a log file unless you uncomment it.
## Just make sure the location that you're storing the logfile is writable by the zabbix user
## In this example, I've used /usr/lib/zabbix/logfiles but this could be anywhere writable by the zabbix user
#f = open('/usr/lib/zabbix/logfiles/snow.log','a')
#f.write('\n\nScript Start :: '+datetime.datetime.now().ctime()+'\n\n')
#f.write(','.join(sys.argv)+'\n')

## Zabbix Passes the details via command line arguments.
assignmentgroup = sys.argv[1]
description = sys.argv[2]
detail = sys.argv[3]

## Set Up your Zabbix details
zabbixsrv = "127.0.0.1"
zabbixun = "Admin"
zabbixpw = "zabbix"

## Set up your ServiceNow instance details
## For Dublin+ instances, connect using JSONv2, otherwise use JSON
username = "username"
password = "password"
instance = "instance"
api = "JSONv2"

## I've configured Zabbix to only pass the Event ID in the message body.
## If you want more detail in the body of the incident in ServiceNow, you'll need to make sure that eventid is parsed out of detail correctly.
eventid = detail

#f.write('trying to connect to servicenow\n')
try:
conn = servicenow.Connection.Auth(username=username,password=password,instance=instance, api=api)
except:
print "Error Connecting to ServiceNow\n"
#f.write("Error Connecting to ServiceNow\n")

#f.write('trying to create incident instance\n')
try:
inc = servicenow.ServiceNow.Incident(conn)
except:
print "Error creating incident instance\n"
#f.write("Error creating incident instance\n")

#f.write('trying to create new incident\n')

## This is where the fun starts.
## You'll need to set up the following section with the correct form fields, as well as the default values
try:
newinc = servicenow.ServiceNow.Incident.create(inc, { \
"short_description":description, \
"description":detail, \
"priority":"3", \
"u_requestor":"autoalert", \
"u_contact_type":"Auto Monitoring", \
"assignment_group": assignmentgroup})
#f.write("\n\n"+str(newinc)+"\n\n")
except Exception as e:
print "Error creating new incident in ServiceNow\n"
print str(e)
#f.write("Error creating new incident in ServiceNow\n")
#f.write(str(e)+"\n")

## This script will retrieve the new incident number from servicenow and put it back into zabbix as an acknowledgement
try:
newincno = newinc["records"][0]["number"]
except:
print "unable to retrieve new incident number\n"
#f.write("unable to retrieve new incident number\n")

zabbix = zapi.ZabbixAPI(url='http://'+zabbixsrv+'/zabbix',user=zabbixun,password=zabbixpw)
zabbix.login()
#f.write('Acknowledging event '+eventid+'\n')
zabbix.Event.acknowledge({'eventids':[eventid],'message':newincno})

#f.write('\n\nScript End :: '+datetime.datetime.now().ctime()+'\n\n')
#f.close()

Share
Jun 272013
 

I’ve been building a “Stats Grabber” for one of the managers at work. The ServiceNow instance that I’m using only has the XML interface enabled at the moment so I’ll be using that.

This will just be a quick overview of what I’ve used to build this, won’t go into the details too much as each configuration will differ.
The stats that I needed were to be sorted by day, so I’ve defined a function that will return an array that each day will have.
I’ve cut down what I actually had but this gives you a good example.

function CreateArray() {
return array(
"req"=>"0",
"inc"=>"0",
"incMajor"=>"0",
"contacttypePhone"=>"0",
"contacttypeEmail"=>"0",
"contacttypeOther"=>"0",
"contacttypeAuto"=>"0",
"totalTickets"=>"0",
"reqResolved"=>"0",
"incResolved"=>"0",
"totalReqInc"=>"0",
"reqResBySD"=>"0",
"incResBySD"=>"0",
"totalResBySD"=>"0"
);
}

Next up is defining the URLs that are used to retrieve data.
The $instance variable will need to be defined.

// Request Queries
$requrl = "https://".$instance.".service-now.com/u_request_list.do?XML&sysparm_query=u_requestor!%3D9faaf5b90a0a7813005cc0d4347713bc%5Esys_created_onONDateRange%40javascript%3Ags.dateGenerate('".$_POST['startdate']."'%2C'start')%40javascript%3Ags.dateGenerate('".$_POST['enddate']."'%2C'end')";
$resolvedrequrl = "https://".$instance.".service-now.com/u_request_list.do?XML&sysparm_query=u_requestor!%3D9faaf5b90a0a7813005cc0d4347713bc%5Eu_resolvedONDateRange%40javascript%3Ags.dateGenerate('".$_POST['startdate']."'%2C'start')%40javascript%3Ags.dateGenerate('".$_POST['enddate']."'%2C'end')";

// Incident Queries
$incurl = "https://".$instance.".service-now.com/incident_list.do?XML&sysparm_query=sys_created_onONDateRange%40javascript%3Ags.dateGenerate('".$_POST['startdate']."'%2C'start')%40javascript%3Ags.dateGenerate('".$_POST['enddate']."'%2C'end')";
$resolvedincurl = "https://".$instance.".service-now.com/incident_list.do?XML&sysparm_query=u_resolvedONDateRange%40javascript%3Ags.dateGenerate('".$_POST['startdate']."'%2C'start')%40javascript%3Ags.dateGenerate('".$_POST['enddate']."'%2C'end')";

You may also notice the $_POST variables in the url, these will need to be passed to this script in the YYYY-MM-DD format. These will also be used later to construct the array for the days.

I’ve used CURL to retrieve the data, but there are a few different ways to do this
This snippet will create the $ch handle;

$ch = curl_init();
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($ch, CURLOPT_USERPWD, $un .":". $pw);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);

Next we’ll start getting the data.


// Get Requsts
curl_setopt($ch, CURLOPT_URL, $requrl);
$reqreturn = curl_exec($ch);

// Get Incidents
curl_setopt($ch, CURLOPT_URL, $incurl);
$increturn = curl_exec($ch);

// Get Resolved Requests
curl_setopt($ch, CURLOPT_URL, $resolvedrequrl);
$resreqreturn = curl_exec($ch);

// Get Resolved Incidents
curl_setopt($ch, CURLOPT_URL, $resolvedincurl);
$resincreturn = curl_exec($ch);

curl_close($ch);
// Curl End

I haven’t put in any error capturing but that is something that should be there to catch any errors when trying to retrieve the data.

Now to create the array that will contain all of our data.
As I wanted the data sorted by days, I’ve used a for loop with the start and end dates to create the array.

$DateArray = array();
if(isset($_POST['startdate']) && isset($_POST['enddate'])) {
$start = new DateTime($_POST['startdate']);
$end = new DateTime($_POST['enddate']);
$diff = $start->diff($end)->format("%a");
for($x = 0; $x < $diff+1; $x++) { $datestamp = date("Y-m-d",strtotime("+$x days",strtotime($start->format("Y-m-d"))));
$DateArray[$datestamp] = CreateArray();
}
}

Now we’ll start processing the data.
I’ll only post one of the four blocks for brevity as they’re esssentially the same with minor differences when it comes down to the data.
SimpleXML is used here to parse the xml output of ServiceNow

// Load Incidents XML
$xml = simplexml_load_string($increturn);
// Get Total Incidents
$incTotal = $xml->incident->count();
// Parse incidents for date
foreach($xml->incident as $item) {
$datestamp = date("Y-m-d",strtotime("+8 hours",strtotime($item->opened_at)));
$DateArray[$datestamp]["inc"]++;
$DateArray[$datestamp]["totalTickets"]++;
if($item->priority < 3) { $DateArray[$datestamp]["incMajor"]++; $totalMajorInc++; } switch($item->contact_type) {
case "Email":
$DateArray[$datestamp]["contacttypeEmail"]++;
break;
case "phone":
$DateArray[$datestamp]["contacttypePhone"]++;
break;
case "Auto Monitoring":
$DateArray[$datestamp]["contacttypeAuto"]++;
break;
default:
$DateArray[$datestamp]["contacttypeOther"]++;
break;
}
}

Once all four of those blocks have been executed, you now have the data all in a nice array.
You can then use a foreach loop on the DateArray array to get your data out

Share