HP OMi – Script-Based Email Integration

White paper

Executive summary ...... 2 Background ...... 3 Solution description ...... 4 Basic Email script using JavaMail ...... 4 HTML Email script using JavaMail ...... 4 HTML Email script using MarkupBuilder and AntBuilder ...... 5 MarkupBuilder ...... 5 AntBuilder ...... 6 How to include Ant in the OPR Scripting Host ...... 6 Appendix A: Basic Email using JavaMail ...... 8 Appendix B: HTML Email using JavaMail ...... 10 Appendix C: HTML Email using MarkupBuilder and AntBuilder ...... 14 Troubleshooting ...... 17 For more information ...... 18

Executive summary

This document describes several scripting approaches for generating an email from an OMi event. This includes basic email and HTML formatted email, firstly using Java and then the improvements in conciseness and readability that can be achieved by using Groovy MarkupBuilder and Apache Ant’s mail task.

2 Background

BSM includes an email notification capability out-of-the-box. However, there are several potential limitations: • Email format is plain text, with minimal formatting capability. • Cause/symptom variables are not available in the notification template. • Can require multiple different event filters mapped to different notification templates to adjust email content based on the event attributes (eg, event field might be empty, so want to set a default value). These issues can be addressed by a custom script-based solution which can: • Generate HTML formatted email, which can include graphics and hyperlinks. • Include a hyperlink to the cause event, if applicable. • Embed logic to determine email content, such as set the Incident Number to ‘Not forwarded’ if there is no Incident Number for that event.

3 Solution description

The solution requires a Groovy script which can look up the correct destination email address, based on the selected OMi event. This solution relies on a Custom Attribute (CA) in the OMi event to determine which email address to send the event to. The CA was set in the CI TenantOwner attribute by the OwnerResolver EPI script. Refer to the BSM Extensibility Guide version 9.21 for details. You could choose other criteria for determining the email address(es) – eg Category, assignedTo, etc. Or you could hijack the TenantsUses attribute, since this is a string list for more easily adding/removing email addresses. Either way, it is more efficient if the email address is already contained in an event attribute rather than having to use the RTSM API (Java or Web Service) to perform a lookup of an attribute for the Related CI of the event. If the email address is not available in the event, then the script falls back to a default email address specified in the script. The solution includes information about the cause, in the case where the event itself is a symptom. Due to the nature of TBEC and SBEC, it can take several minutes for an event to be marked as a symptom of a cause event. Therefore, the script should either be executed via Time-Based Event Automation (TBEA) or manually by an operator as a Custom Action, once sufficient time has elapsed for a correlation to have occurred.

Basic Email script using JavaMail The most basic Groovy script is shown in Appendix A: Basic Email using JavaMail. This can be implemented as either a TBEA or Custom Action. It uses JavaMail and requires two files to be added to the classpath of the script: activation.jar and mail.jar. The benefit of this approach is that it is quick and simple to implement. The downside is that it does not create an HTML email.

HTML Email script using JavaMail The basic email script can be enhanced to include HTML markup and the result is shown in Appendix B: HTML Email using JavaMail. Again, it requires the 2 jar files to be added to the classpath. This script includes some processing logic to determine the content of the email based on whether the event is a BPM event or not. If it is a BPM event then the BPM Performance URLs are included in the event, along with the Description and Location. Being HTML, it includes an image (the HP Logo). This script assumes the image is on the Gateway server in /opt/HP/BSM/AppServer/webapps/site.war/HPR_Blue_RGB_150_SM.png. Refer to Figure 1 for an example of the email that is generated.

4

Figure 1. HTML email of BPM event

HTML Email script using MarkupBuilder and AntBuilder The script is now more difficult to read and therefore error prone. There are two ways to improve this script: use MarkupBuilder and AntBuilder. The end result is shows in Appendix C: HTML Email using MarkupBuilder and AntBuilder. The remainder of this document explains the use of MarkupBuilder and AntBuilder.

MarkupBuilder MarkupBuilder is a Groovy helper class for creating XML or HTML markup. It makes the script much more readable. To illustrate the point, the following example is a Custom Action which generates HTML to a file.

import com.hp.opr.api.scripting.Event import groovy..MarkupBuilder class FileExporter {

def init() {} def destroy() {}

def process(List events) { for (Event event: events) fileEvent(event) }

5 def fileEvent(Event event) { def writer = new FileWriter('carol.html') def myhtml = new MarkupBuilder(writer) myhtml.html { body { h1 'Heading' p 'My first paragraph' p { b 'Title: ' mkp.yield event.title } } } } }

# cat /opt/HP/BSM/bin/carol.html

Heading

My first paragraph

Title: Service Type VoIP is not reachable from QA Site Advantage to Advantage.

AntBuilder Apache Ant is a build environment for Java projects like in C but the build files are written in XML. Groovy provides Ant integration through its AntBuilder class. AntBuilder builds Ant projects that contain a nested set of build instructions. It interfaces directly with the Ant API, so the normal Ant XML build file is skipped altogether. This combines the scripting language strength of Groovy with the concise and more readable syntax from AntBuilder. Ant supports sending emails through its mail task and it is this component being used in the solution. This shortens the part sending the mail. However, the downside is that you need to do a few extra steps to include Ant in the OPR Scripting Host.

How to include Ant in the OPR Scripting Host Perform these steps on the Gateway Server if you are calling the email script from a Custom Action. Perform these steps on the DPS if you are calling the email script from a TBEA. 1. Download and install Ant http://ant.apache.org/bindownload.cgi Get apache-ant-1.8.4-bin.tar.gz

# gunzip apache-ant-1.8.4-bin.tar.gz # tar xvf apache-ant-1.8.4-bin.tar This creates a directory called apache-ant-1.8.4 containing the files.

# ll apache-ant-1.8.4/ total 372 6 drwxr-xr-x 2 root root 4096 Jan 29 15:01 bin drwxr-xr-x 3 root root 4096 Jan 29 15:01 etc -rw-r--r-- 1 root root 11253 May 21 2012 fetch.xml -rw-r--r-- 1 root root 4445 May 21 2012 get-m2.xml -rw-r--r-- 1 root root 126 May 21 2012 INSTALL -rw-r--r-- 1 root root 86299 May 21 2012 KEYS drwxr-xr-x 2 root root 4096 Jan 29 15:01 lib -rw-r--r-- 1 root root 15289 May 21 2012 LICENSE drwxr-xr-x 8 root root 4096 Jan 29 15:01 manual -rw-r--r-- 1 root root 218 May 21 2012 NOTICE -rw-r--r-- 1 root root 4119 May 21 2012 README -rw-r--r-- 1 root root 209711 May 21 2012 WHATSNEW

# mv apache-ant-1.8.4 /opt/HP/BSM/opr

2. Copy mail.jar into the ant directory

# cp /opt/HP/BSM/EJBContainer/client/mail.jar /opt/HP/BSM/opr/apache- ant-1.8.4/lib

3. Edit OPR Scripting Host startup script to include ant/lib jar files

# vi /opt/HP/BSM/bin/opr-scripting-host_run.sh Find this line:

SERVICE_MANAGER_OPTS="-DhacProcessName=$INTERNAL_PROCESS_NAME - Dlog.folder.path.output=$INTERNAL_PROCESS_NAME - Dlog.folder=$INTERNAL_PROCESS_NAME -DuseCustomClassLoader=true - DcustomClassLoaderDirs=opr/lib,lib"; export SERVICE_MANAGER_OPTS Modify it to include opr/apache-ant-1.8.4/lib:

SERVICE_MANAGER_OPTS="-DhacProcessName=$INTERNAL_PROCESS_NAME - Dlog.folder.path.output=$INTERNAL_PROCESS_NAME - Dlog.folder=$INTERNAL_PROCESS_NAME -DuseCustomClassLoader=true - DcustomClassLoaderDirs=opr/apache-ant-1.8.4/lib,opr/lib,lib"; export SERVICE_MANAGER_OPTS

4. Restart the OPR Scripting Host service:

# cd /opt/HP/BSM/opr/support # ./opr-support-utils.sh -stop OPR-SCRIPTING-HOST # sleep 20 # ./opr-support-utils.sh -start OPR-SCRIPTING-HOST

7

Appendix A: Basic Email using JavaMail

import javax.mail.internet.*; import javax.mail.*; import javax.activation.*; import java.util.List; import com.hp.opr.api.scripting.Event; class GroovyScriptSkeleton { def init() {

}

def destroy() {

}

def process(List events) {

events.each { event -> modifyEvent(event);

}

}

def modifyEvent(Event event) {

def toAddress = "[email protected]"; def fromAddress = "[email protected]"; def host = "localhost"; def port = "25";

def nodeHints = event.getNodeHints(); def nodeName = nodeHints.getDnsName();

if (event.getCustomAttribute("Email Contact") != null) {

toAddress = event.getCustomAttribute("Email Contact"); }

def subject = "BSM Notification: " + event.getSeverity() + " on " + nodeName;

def message = event.getTitle() + "\n\n" + "Node Name: " + nodeName + "\n" + "Priority: " + event.getPriority() + "\n" + "Severity: " + event.getSeverity() + "\n" + "Time Received: " + event.getTimeReceived();

if (event.getCause() != null) {

8 message = message + "\n\nCause event: " + "http://enright.rose.hp.com/opr-console/opr-evt-details?eventId=" + event.getCause(); }

Properties mprops = new Properties(); mprops.setProperty("mail.transport.protocol","smtp"); mprops.setProperty("mail.host",host); mprops.setProperty("mail.smtp.port",port);

Session lSession = Session.getDefaultInstance(mprops,null); MimeMessage msg = new MimeMessage(lSession);

//tokenize out the recipients in case they came in as a list StringTokenizer tok = new StringTokenizer(toAddress,";"); ArrayList emailTos = new ArrayList(); while(tok.hasMoreElements()){ emailTos.add(new InternetAddress(tok.nextElement().toString())); } InternetAddress[] to = new InternetAddress[emailTos.size()]; to = (InternetAddress[]) emailTos.toArray(to); msg.setRecipients(MimeMessage.RecipientType.TO,to); InternetAddress fromAddr = new InternetAddress(fromAddress); msg.setFrom(fromAddr); msg.setFrom(new InternetAddress(fromAddress)); msg.setSubject(subject); msg.setText(message) //msg.setContent(message, "text/html")

Transport transporter = lSession.getTransport("smtp"); transporter.connect(); transporter.send(msg);

}

}

9

Appendix B: HTML Email using JavaMail

import javax.mail.internet.*; import javax.mail.*; import javax.activation.*; import java.util.List; import com.hp.opr.api.scripting.Event; class GroovyScriptSkeleton { def init() {

}

def destroy() {

}

def process(List events) {

events.each { event -> modifyEvent(event);

}

}

def modifyEvent(Event event) {

def toAddress = "[email protected]"; def fromAddress = "[email protected]"; def host = "localhost"; def port = "25"; def subject = "BSM Notification: "; def mess_html_header = "

\ \ \ \ \ \
HP Business Service Management
";

def mess_html_start = "

\ \ "

def nodeHints = event.getNodeHints(); def nodeName = nodeHints.getDnsName();

10

if (event.getCustomAttribute("Email Contact") != null) {

toAddress = event.getCustomAttribute("Email Contact"); }

if (event.getSubCategory() == "bpm.transaction.alert.type") { subject = subject + event.getSeverity() + ": " + event.getTitle(); mess_html_start = mess_html_start + "\

\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ "

} else { subject = subject + event.getSeverity() + " on " + nodeName; mess_html_start = mess_html_start + "\

\ 11 \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ "

}

def mess_html_end = "

Title" + event.getTitle() + "
Description" + event.getDescription() + "
Business Service" + event.getCustomAttribute("Business Service") + "
Location" + event.getCustomAttribute("Location Name") + "
Priority" + event.getPriority() + "
Severity" + event.getSeverity() + "
Time Received" + event.getTimeReceived() + "
Incident" + event.getControlTransferredTo().getExternalId() + "
BPM ReportsBPM Performance Analysis Report \
BPM Triage Report
Title" + event.getTitle() + "
Node Name" + nodeName + "
Business Service" + event.getCustomAttribute("Business Service") + "
Priority" + event.getPriority() + "
Severity" + event.getSeverity() + "
Time Received" + event.getTimeReceived() + "
Incident" + event.getControlTransferredTo().getExternalId() + "
"

if (event.getCause() != null) { mess_html_end = "CauseCause event" }

Properties mprops = new Properties(); mprops.setProperty("mail.transport.protocol","smtp"); mprops.setProperty("mail.host",host); mprops.setProperty("mail.smtp.port",port);

Session lSession = Session.getDefaultInstance(mprops,null); MimeMessage msg = new MimeMessage(lSession);

//tokenize out the recipients in case they came in as a list StringTokenizer tok = new StringTokenizer(toAddress,";"); ArrayList emailTos = new ArrayList(); while(tok.hasMoreElements()){ emailTos.add(new InternetAddress(tok.nextElement().toString())); } InternetAddress[] to = new InternetAddress[emailTos.size()]; to = (InternetAddress[]) emailTos.toArray(to); msg.setRecipients(MimeMessage.RecipientType.TO,to); 12 InternetAddress fromAddr = new InternetAddress(fromAddress); msg.setFrom(fromAddr); msg.setFrom(new InternetAddress(fromAddress)); msg.setSubject(subject); //msg.setText(message) msg.setContent(mess_html_header + mess_html_start + mess_html_end, "text/html");

Transport transporter = lSession.getTransport("smtp"); transporter.connect(); transporter.send(msg);

}

}

13

Appendix C: HTML Email using MarkupBuilder and AntBuilder

import com.hp.opr.api.scripting.Event import groovy.xml.MarkupBuilder class MailExporter { String mailHost = "localhost" int port = 25 String defaultMailTo = "[email protected]" String defaultMailFrom = "[email protected]"

def init() {} def destroy() {}

def process(List events) { for (Event event: events) mailEvent(event) }

def mailEvent(Event event) { boolean isBpmEvent = event.getSubCategory().equals("bpm.transaction.alert.type") String nodeName = event.nodeHints?.dnsName ?: '(no node)' StringWriter writer = new StringWriter() def myhtml = new MarkupBuilder(writer) myhtml.html { table (border: 0, cellpadding: 10) { tr (bgcolor: 'white') { td { img (src: 'http://bsm.rose.hp.com/topaz/HPR_Blue_RGB_150_SM.png', height: 50, width: 50, alt: 'HP logo') } td { b('HP Business Service Management') } } } table (border: 0, width: '100%', cellpadding: 10, bgcolor: 'white') { col (width: 50) col (width: 100) tr { td { b('Title') } td (event.title) } if (isBpmEvent) { tr { td { b('Description') } td (event.description) } tr { td { b('Location') } 14 td (event.getCustomAttribute("Location Name")) } } else { tr { td { b('Node Name') } td (nodeName) } } tr { td { b('Business Service') } td (event.getCustomAttribute("Business Service")) } tr { td { b('Priority') } td (event.priority) } tr { td { b('Severity') } td (event.severity) } tr { td { b('Time Received') } td (event.timeReceived) } tr { td { b('Incident') } td (event.controlTransferredTo?.externalId ?: ' Not forwarded') } if (isBpmEvent) { td { b('BPM Reports') } td { a (href: event.getCustomAttribute("BPMPerfAnalysisReportUrl"), target: '_blank', 'BPM Anaysis Report') br() a (href: event.getCustomAttribute("BPMTriageReportUrl"), target: '_blank', 'BPM Triage Report') } } if (event.cause != null) { tr { td { b('Cause') } td { a (href: 'http://bsm.rose.hp.com/opr-web/opr-evt- details?eventId=' + event.cause, target: '_blank', 'Cause event') } } } } }

String toAddress = event.getCustomAttribute("Email Contact")?.replace(';', ',') ?: defaultMailTo String subject if (isBpmEvent) subject = "BSM Notification: $event.severity : $event.title" else subject = "BSM Notification: $event.severity on $nodeName" def ant = new AntBuilder() ant.mail(mailhost: mailHost, mailport: port, subject: subject, messagemimetype: 'text/html') { from(address: defaultMailFrom) to(address: toAddress) message(writer) 15 } }

}

16 Troubleshooting

When you save the Groovy script, BSM performs some syntax checking. If there are errors, then these are written to the BSM GW or DPS (depending if it is executed from a Custom Action or TBEA) in /log/opr-scripting-host/scripts.log and /log/opr-scripting-host/opr-scripting-host.log.

17 For more information

http://support.openview.hp.com/selfsolve/manuals

HP Business Service Management for the Windows®, Linux operating systems: BSM Extensibility Guide, Version 9.21, November 2012

On the HP BSM Gateway Server, the Java API documentation is available at:

/AppServer/webapps/site.war/Amdocs/eng/doc_lib/API_docs/UCMDB _JavaAPI\index.html

© 2012 Hewlett-Packard Development Company, L.P. The information contained herein is subject to change without notice. The only warranties for HP products and services are set forth in the express warranty statements accompanying such products and services. Nothing herein should be construed as constituting an additional warranty. HP shall not be liable for technical or editorial errors or omissions contained herein.

Microsoft® and Windows® are U.S. registered trademarks of Microsoft Corporation. Oracle® is a registered US trademark of Oracle Corporation, Redwood City, California.

UNIX® is a registered trademark of The Open Group. June 2012

18