Integration with the IA and Communications Plans (GIG part 6)

Welcome back!

 

Master Chef is very pleased with his customer notification system that we set up back in part 2, added inbound email support in part 3, and then added support for muffin reservations in part 5. There are some things he might want to add later, but he has a more pressing issue right now... 

 

With all this new business, Master Chef had trouble keeping up with demand. So he did two things: he hired an intern, Intern Ivan; and then he ordered some fancy new Smart Ovens™. These are so smart (the ovens, not the Intern) they have a small Linux OS running on them and a wi-fi card to support the move to "The Internet of Things" (or IoT for short). 

 

Unfortunately, Intern Ivan was distracted by the shiny new ovens and burnt the latest batch of cucumber grape ginger goodies to coal. Master Chef needs a way to be notified when the goodies are done! Fortunately, the xMatters Integration Agent can do the job. Read on to find out how we install the integration agent (IA) and use the new communication plan support to fire notifications from a tool as simple as an oven!

 

The Internet of Things is all about connecting anything that uses electricity to lots of other things that use electricity. In this case, we are going to connect these fancy new smart ovens to the xMatters API to send notifications. After this post, the ovens will be able to send a text message, voice, email, or even a mobile push!

 

First, we need to download the latest IA (5.1.4 introduced native support for communication plans). The latest IA can be found on the Integration Agent home page. There are plenty of other resources there to get started, but for now, we'll just download the Linux 64-bit IA (these are top of the line ovens here). 

 

The integration agent is a powerful tool for building integrations, especially on simple devices such as an oven or with applications that cannot make web service calls. The additional functionality to queue messages and provide a Javascript environment for enriching events makes it a powerful tool in our integrations tool box. 

 

While that IA was downloading, I put together a communication plan (check out part 2 on details about how to do such a thing) specific to Oven Notifications. I created three properties that seem like they might be useful: Oven_Name, Timer_End_Time, and Timer_Start_Time. I'll explain why we use the underscores (_) when we talk about the IA below. 

 

I then created a form for "Timer Finished" and added all three properties to the layout. Once you load it in, don't forget to enable the plan and select the Create Event Web Service option. 

 

Hop over to the Users page and create a new user. If you don't have the REST Web Services User role, contact your friendly CSM or open a ticket with support. Or, for now you can use the Full Access User role. My user is called "ovens":

Ok, then give the "ovens" user permissions to use our Timer Finished form. Just click Permissions in the "Web Service Only" drop down next to the form name, enter "ovens" in the dialog box displayed, and then hit Save Changes. 

 

Sweet! Our xMatters environment is mostly set up for our integration, so let's switch gears and install the IA. Once the zip file is copied over to the oven, unzip it and copy to a sensible installation folder. I typically use: 

/etc/integrationagent-X.X.X

 where X.X.X is the version. This helps keep things out of my user's home directory and immediately tells me what version of the IA I am running. Make sure to set the <company> and <user> tags as appropriate in the <IAHOME>/conf/IAConfig.xml.

Also make sure to run the iapassword utility to set the IA user password. More details can be found in the Integration Agent docs here, or post a question on the forum if you need some extra eyes. 

Inside the <IAHOME>/integrationservices directory you'll see several sample integrations:

[ovens@theoven1 integrationservices]$
[ovens@theoven1 integrationservices]$ ll
total 28
drwxrwxr-x 3 ovens ovens 4096 Jan 12 22:08 applications
drwxrwxr-x 4 ovens ovens 4096 Jan 19 23:42 autoloaded
drwxrwxr-x 3 ovens ovens 4096 Jan 19 23:42 generic
drwxrwxr-x 3 ovens ovens 4096 Jan 19 23:42 ping
drwxrwxr-x 3 ovens ovens 4096 Jan 19 23:42 sample
[ovens@theoven1 integrationservices]$
 

 

Most of these are actually older "APXML" integrations, however, in the "applications" directory you'll notice a "sample-relevance-engine" directory. This contains a very simple example of how to build a communication plan integration from the IA. Just what the chef ordered! 

 

Copy the contents of that "sample-relevance-engine" directory into a new directory called <IAHOME>/integrationservices/ovens. Then change the file names from sample-relevance-engine.* to ovens.* and go ahead and delete the SampleRelevanceEngine.zip file. This is the Communication Plan you load into the xMatters UI, but we created ours above, so we don't need this one. Once you are done with this part, your directory should look like this:

[ovens@theoven1 integrationservices]$ pwd /etc/integrationagent-5.1.4/integrationservices [ovens@theoven1 integrationservices]$ ll ./ovens/
total 16
-rw-rw-r-- 1 ovens ovens 1776 Jan 22 17:31 configuration.js
drwxr-xr-x 4 ovens ovens 4096 Jan 22 17:31 dynamic
-rw-rw-r-- 1 ovens ovens 730 Jan 22 17:31 ovens.js
-rw-rw-r-- 1 ovens ovens 1104 Jan 22 17:31 ovens.xml
[ovens@theoven1 integrationservices]$
 

Getting closer. Before we get into tweaking these files for our needs, let's go over the function of each file and why we care about it. 

  • configuration.js - Contains the communication plan web services URL which I sometimes refer to as the endpoint. Also contains the username, what callbacks to use and the deduplication filter name. 
  • dynamic - A temporary directory that holds files compiled by the IA. Can be ignored. If you delete it, fret not, it will be re-created. Trust me. 
  • ovens.js - The javascript file that deals with incoming requests that are passed to On-Demand as well as any responses from a user to xMatters and then back to the IA. The brains of the operation. 
  • ovens.xml - This is the configuration file for the IA. This tells the IA what the integration name is, as well as parameters and what javascript file to run when stuff happens. Very important. 

We'll dig into the items that relate to this post, but the other stuff we'll leave for a later post.... 

First, crack open that ovens.xml file with your favorite text editor. Here again, we'll need to change all references from "sample-relevance-engine" to "ovens". Also note the xmpassword file path near the bottom needs updating. Finally, we need to add the mapped-input parameters and these, uncoincidentially, will match up with our property names in the Communication Plan in xMatters. 

 

Once you are done with all that, the file should look like this. Make sure to keep the domain value as "applications". 

<?xml version="1.0" encoding="UTF-8"?>
<!--
| Service configuration file for the applications domain.
|
| attribute: version
| values : 1.0
| comments : identifies the format version of this file
|
| attribute: xmlns
| values : http://www.alarmpoint.com/schema
| comments : the default namespace in which all elements and attributes are
| defined
+-->
<integration-service xmlns="http://www.alarmpoint.com/schema" version="1.0">
<domain>applications</domain>
<name>ovens</name>
<initial-state>active</initial-state>
<script lang="js">
<file>ovens.js</file>
</script>
<classpath />
<mapped-input method="add">
<parameter>recipients</parameter>
<parameter>Oven_Name</parameter>
<parameter>Timer_End_Time</parameter>
<parameter>Timer_Start_Time</parameter>
</mapped-input>
<constants>
<encrypted-constant name="xmpassword" type="string" overwrite="true">
<file>integrationservices/ovens/.initiatorpasswd</file>
</encrypted-constant>
</constants>
</integration-service>

I mentioned something about it above, but we have to be careful of what we name the properties. The plan properties page will allow you to put pretty much whatever character you want. So the UI will let us create a property named "Oven Temp° & Humidity < 50 %", but the integration agent needs to read these names as ASCII characters that get stuffed into XML element name (and then eventually JSON, but we'll get to that later), so we can't just willy nilly name our properties. Also note that if you put the parameter name here with a space, the IA will replace the space ( ) with an underscore (_). 

 

I also added a mapped-input parameter called "recipients". Guess what this will be. I'll give you 5 tries. Yep, the recipients of the event. This can be a group name or a user name. I think you might be able to use a device name, but I've never tried. If you have success with it, post up in the comments. 

 

The last thing to note here is the .initatorpasswd file. This is an encrypted file with the rest user's password. So we set the username below in configuration.js, but we have to set the password somewhere and that somewhere is the .initatorpasswd file. This file is created with the <IAHOME>/bin/iapassword script. I always forget the format of this command, but calling it with no parameters prints a helpful message to remind me. From there, I then can pass the right information in the right place. 

[ovens@theoven1 bin]$ ./iapassword.sh
Usage: iapassword --new <new_password> [--old <old_password>] [--file </path/to/pwd/file>]
[ovens@theoven1 bin]$
[ovens@theoven1 bin]$ ./iapassword.sh --new ovens --file integrationservices/ovens/.initiatorpasswd
Saving password to /etc/integrationagent-5.1.4/integrationservices/ovens/.initiatorpasswd
Password changed successfully. Please run iadmin reload all or restart the Integration Agent for your changes to take effect.

 

The next step is to crack open the ovens.js file and update the path to the configuration.js file. The "load" function used here is very hand for including other java script files. Here, we are loading the event.js file that contains all the helper objects for creating events and also loading this configuration file which we'll edit in a moment. 

///////////// Javascript
load("lib/integrationservices/javascript/event.js");
load("integrationservices/ovens/configuration.js");
function apia_remapped_data() {
  return {
    "priority" : "priority"
  }
}
function apia_event(form) {
  //The comment below demonstrates how to update a property value.
  // form.properties.city = "Victoria";
  IALOG.info( 'Properties: JSON: ' + JSON.stringify( form.properties ) );
  return form;
}
function apia_callback(msg) { var str = "Received message from xMatters:\n"; str += "Incident: " + msg.incident_id; str += "\nEvent Id: " + msg.eventidentifier; str += "\nCallback Type: " + msg.xmatters_callback_type; IALOG.info(str); }

 

I'm going to ignore most of this file for now and focus on the items we need. The item in particular is the "apia_event" function. This is called when the IA receives input directed at this integration service. Anything put in here can operate on, read or do other things to move (or not move) the event along the workflow. In this case, we are logging all of the properties we receive to the log. 

 

Once you save that file, open the configuration.js file in your text editor of choice (emacs camp can be forgiven for their wayward ways). As before remove references to the "sample-relevance-engine" and replace with "ovens". Set the callbacks to an empty array and finally, grab the web service URL from the communication plan in the xMatters user interface. It should look something like this:

// -----------------------------------------------------------------------------------
// Configuration settings for an xMatters Communication Plan Integration
// -----------------------------------------------------------------------------------

// ----------------------------------------------------------------------------------------
// The url that will be used to inject events into xMatters.
// ----------------------------------------------------------------------------------------
WEB_SERVICE_URL = "https://company.dc.xmatters.com/reapi/2015-01-01/forms/UUID-GOES-HERE/triggers";

// ----------------------------------------------------------------------------------------
// Callbacks requested for this integration service.
// ----------------------------------------------------------------------------------------
CALLBACKS = [];

// ----------------------------------------------------------------------------------------
// The username used to authenticate the request to xMatters.
// The user's password should be encrypted using the iapassword.sh utility.
// Please see the integration agent documentation for instructions.
// ----------------------------------------------------------------------------------------------------
INITIATOR = "ovens";

// ----------------------------------------------------------------------------------------------------
// Filter to use in /conf/deduplicator-filter.xml
// ----------------------------------------------------------------------------------------------------
DEDUPLICATION_FILTER_NAME = "ovens";

 

One thing to mention here, the deduplication filter helps prevent a spam overload to the xMatters On-Demand system. It lets the IA filter out the 999 other events that a system might send it when we really just needed that first one. The next step is to tell the IA about what criteria we want to deduplicate on. This is stored in the <IAHOME>/conf/deduplicator-filter.xml file. Open that one and navigate to the bottom. Before the last </deduplicator> tag, add this snippet:

<filter name="ovens">
  <predicates>
    <predicate>Timer_Start_Time</predicate>
  </predicates>
  <suppression_period>1</suppression_period>
  <window_size>100</window_size>
</filter>

 

This tells the IA to look at "Timer_Start_Time" and if something comes in with the same value for this parameter within the 1 second suppression_period, then don't pass along the event and make a note in the log. The log part is part of the core code and not actually in that snippet, so no need to adjust your glasses. 

 

Ok, the last piece of all this is to register this new directory and code as an integration service with the IA. We do this by adding an entry to the <IAHOME>/conf/IAConfig.xml. Near the bottom, you'll see an entry for "service-configs". Add a new line for ovens/ovens.xml like so:

  <path>applications/sample-relevance-engine/sample-relevance-engine.xml</path>
  <path>sample/sample.xml</path>
  <path>ping/ping.xml</path>
  <path>generic/generic.xml</path>
  <path>ovens/ovens.xml</path> <!-- Add this line -->

 

Once that is all set, fire up the IA and let's run a test. You can start the IA with the "start_daemon" script (*nix systems, or as a windows service, but no self respecting oven would run windows). When it is successfully running, we can test sending an event using the command line. Navigate to the <IAHOME>/bin directory and run this command:

./APClient.bin --map-data 'applications|ovens' '[{"targetName":"chef"}]' "oven1" "10:34 AM" "11:04 AM"
 
Before we look at the output, I'll explain what each piece does:
  • APClient.bin - This is an executable script that reads command line options and invokes (or tries to invoke!) an integration service or gets information about the status of the IA. 
  • --map-data - Tells APClient bin that we are going to pass some parameters via command line and that the next parameter is the integration service followed by the event parameters. 
  • 'applications|ovens' - This should match the value of the <domain> and <name> tags in the xml file. In our case this happens to be "applications" and "ovens", in the sample-relevance-engine integration service, this would be "applications|sample-relevance-engine" because the <name> value says so. 
    • '[{"targetName":"chef"}]' - This exact value will be passed as the "recipients" parameter when the IA makes the REST call. You'll notice it is very similar to the format noted in the example at the bottom of this page. The value is a JSON array of objects that must at least have a "targetName" parameter and can optionally provide a device list to limit the devices. "targetName" can be a user or a group. 
    • oven1 - We know this is the "Oven_Name" parameter because it is after the "recipients" parameter in the <IAHOME>/integrationservices/ovens/ovens.xml mapped-input tag. 
    • "10:34 AM" - Mapped to "Timer_End_Time" as defined in ovens.xml.
    • "11:04 AM" - Mapped to "Timer_Start_Time". 

 I've indented those last 4 to emphasize these are the event parameters and they get their names from the integration service xml file; ovens.xml in this case. 

 

When we execute this command, the IA sends back a message:

[ovens@theoven1 bin]$ ./APClient.bin --map-data 'applications|ovens' '[{"targetName":"chef"}]' "oven1" "10:34 AM" "11:04 AM"
<?xml version="1.0" encoding="UTF-8"?>
<transaction id="1"><header><method>Agent</method><subclass>OK</subclass></header><data/></transaction>[ovens@theoven1 bin]$

 

The OK here means the IA successfully received the command. Notice I did not say "xMatters received". The result of this command just tells us the IA understood the command and will queue it to the appropriate integration service. Fortunately, I've been monitoring the Reports tab on my On-Demand instance, and I see it pop up there. Success!

So, we've just run a test to make sure the IA on at least one of the ovens can create events in our system. At this point, we would talk to the oven manufacturer and learn how they make outbound calls. Every system is different, but any application worth its bits can make some kind of call to the outside world to perform an action. In this post, we've build an inbound command line integration that happens to be one-way only.... for now....

 

 Update! Read on to part 7 for details on getting responses back to the ovens!

 

 

Have more questions? Submit a request

3 Comments

  • 0
    Avatar
    Brannon Vann

    On a Windows install, it's important to escape the double quotes in the recipient parameter where the targetname is set. Also, it needs to be surrounded by double quotes. Here is what i needs to look like when you call APClient.bin.exe: "[{\"targetName\":\"chef\"}]"

    and the full command:

    APClient.bin.exe --map-data "applications|ovens" "[{\"targetName\":\"chef\"}]' "oven1" "10:34 AM" "11:04 AM"

  • 0
    Avatar
    John Pereira

    Hi Travis, This is a good article and i understand some of the terms now. I however still have a problem . Here is what i have done so far.
    I copy pasted the xml and js files from generic folder and put them under PATROL folder. Then i updated the xml and js with relevant data such as domain, name, etc. Now when i run the APClient.bin with mapdata parameters, i do get an email notification on my email id but the content is blank. So i know the IA is working fine, but the mapping is not. I tried to read some documents and including this artcile, but i am still confused on how to map the xml/js to the final alert. Can you help me with this..

  • 0
    Avatar
    Travis DePuy

    John, The key is that "<mapped-input method="add">" section of the ovens.xml file. The order here gives the names to the parameters when sent via command line. I saw you posted in the other thread, so I'll give more detail there.

Please sign in to leave a comment.
Powered by Zendesk