<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
<META NAME="Generator" CONTENT="MS Exchange Server version 6.5.7226.0">
<TITLE>Nagios and RT Integration</TITLE>
</HEAD>
<BODY>
<!-- Converted from text/rtf format -->
<BR>
<P><FONT SIZE=2 FACE="Arial">There seem to be a lot of people looking for information on how to integrate Nagios and RT. This is one solution that I use which might be helpful. Instead of trying to fix RT to accept Nagios e-mails and deal with them in complicated ways, a simpler solution is to alter Nagios. We've been running with this hack, in my office for about a year and it is working fairly well. People in the office have been on my case to share this knowledge with the rest of the RT community, so here it is.</FONT></P>
<P><FONT SIZE=2 FACE="Arial">I use Nagios for various server and service alarms and have it automatically create RT tickets when an alarm is acknowleged. This keeps the RT requests fairly simple and avoids the problem of nagios automatically creating hundreds of tickets that all need to be closed, when nagios keeps sending follow up alarms. It also helps when a server goes down and throws 20 alarms at the same time, but we really only want one ticket open for the entire issue.</FONT></P>
<P><FONT SIZE=2 FACE="Arial">To have Nagios create an RT ticket when an alarm is acknowleged, I have changed the Nagios CGI which does acknowlegements and added the logic to create the RT ticket there. I didn't make any changes to RT or create any scrips. Instead, I added a checkbox to the alarm acknowlegement screen, and created a function to call the RT CLI. It's the RT CLI that does the actual ticket creation. Instead of using the CLI, you could also have used RT's perl api to do the same thing and make your own CLI. In either case you still have to do an exec from the command line because the nagios cgi's are written in C, and you can't just drop the perl in there directly. Anyone have a C interface for RT? </FONT></P>
<P><FONT SIZE=2 FACE="Arial">They key to hacking Nagios to create RT tickets is the nagios's cmd.c file. This is where the acknowlegement code lives. You make your changes there, recompile that file and copy the compiled cmd.cgi into the correct directory (<docroot>/sbin). </FONT></P>
<P><FONT SIZE=2 FACE="Arial">This is what you need to do ….</FONT>
</P>
<P><FONT SIZE=2 FACE="Arial">1) Add a "make_ticket" function that will take the alarm information and the name of the user that is acknowleging the alarm and creates an rt ticket through a system call the RT cli.</FONT></P>
<P><FONT SIZE=2 FACE="Arial">2) Add a check box to the cmd.c cgi to allow a user to select whether or not they want to create an rt ticket when the alarm is acknowleged. This is useful when acknowleging multiple alarms for the same problem and avoiding the creation of multiple usless tickets. </FONT></P>
<P><FONT SIZE=2 FACE="Arial">3) Add logic to both the service and host alarm acknowlegement code to run make_ticket when either service or host problems are acknowleged.</FONT></P>
<P>
</P>
<P><FONT SIZE=2 FACE="Arial">To the Nagios cmd.c I added the following function. It's not the most elegant function and should probably be changed to use real memory allocation, using one cli call to both create the ticket and add the comment, and not using awk, etc. This is left for future development by a better c programmer with more time on his hands.</FONT></P>
<P><FONT SIZE=2 FACE="Arial">===========================</FONT>
</P>
<P><FONT SIZE=2 FACE="Arial">int make_ticket (char * owner, char * subject, char * result)</FONT>
<BR><FONT SIZE=2 FACE="Arial">{</FONT>
<BR><FONT SIZE=2 FACE="Arial"> char rt_command[300];</FONT>
<BR><FONT SIZE=2 FACE="Arial"> FILE * temp_pipe;</FONT>
<BR><FONT SIZE=2 FACE="Arial"> char requestor[40];</FONT>
<BR><FONT SIZE=2 FACE="Arial"> sprintf (requestor, "%s@mycompany.com", owner);</FONT>
</P>
<P><FONT SIZE=2 FACE="Arial"> sprintf (rt_command,"/opt/rt3/bin/rt create -t ticket set status=new subject='%s' owner='%s' queue='Alarms' requestors='%s' admincc='supervisor@mycompany.com' priority='99'", subject,owner,requestor);</FONT></P>
<P><FONT SIZE=2 FACE="Arial"> /* Create the ticket */</FONT>
<BR><FONT SIZE=2 FACE="Arial"> temp_pipe = popen(rt_command,"r");</FONT>
<BR><FONT SIZE=2 FACE="Arial"> if (!temp_pipe)</FONT>
<BR><FONT SIZE=2 FACE="Arial"> {</FONT>
<BR><FONT SIZE=2 FACE="Arial"> result = "Failed to create Ticket";</FONT>
<BR><FONT SIZE=2 FACE="Arial"> }</FONT>
<BR><FONT SIZE=2 FACE="Arial"> else</FONT>
<BR><FONT SIZE=2 FACE="Arial"> {</FONT>
<BR><FONT SIZE=2 FACE="Arial"> fgets(result, 300, temp_pipe);</FONT>
<BR><FONT SIZE=2 FACE="Arial"> sprintf (result, "%s", result);</FONT>
<BR><FONT SIZE=2 FACE="Arial"> }</FONT>
<BR><FONT SIZE=2 FACE="Arial">}</FONT>
</P>
<P><FONT SIZE=2 FACE="Arial">=================================</FONT>
</P>
<P><FONT SIZE=2 FACE="Arial">The following case statement (in cmd.c) deals with host problem acknowlegement. This will be almost exactly the same thing when acknowleging service problems, but in that case you will be looking for "case CMD_ACKNOWLEDGE_SVC_PROBLEM". I'm sure you can also create RT tickets for other types of acknowlegements but I don't bother with those. In the below case statement, notice the boolean variable "do_make_ticket" this is set to true if the "make ticket" checkbox is checked (more info on this later). If someone elects not to create a ticket, the else statement does the standard code for host acknowlegements. The make ticket function returns the result of the ticket creation and I parse that result to display my own success message. I don't do any real exception handling, this has been left for some other C programmer with more time on his hands. Basically if I don't see a ticket number when I test it, I know something is wrong. </FONT></P>
<BR>
<P><FONT SIZE=2 FACE="Arial"> case CMD_ACKNOWLEDGE_HOST_PROBLEM:</FONT>
<BR><FONT SIZE=2 FACE="Arial"> if (do_make_ticket)</FONT>
<BR><FONT SIZE=2 FACE="Arial"> {</FONT>
<BR><FONT SIZE=2 FACE="Arial"> /* create a ticket in request tracker */</FONT>
<BR><FONT SIZE=2 FACE="Arial"> sprintf (subject, "Alarm for %s", host_name);</FONT>
<BR><FONT SIZE=2 FACE="Arial"> sprintf (rt_comment, "%s", comment_data);</FONT>
<BR><FONT SIZE=2 FACE="Arial"> make_ticket (current_authdata.username,subject, rt_comment, ticket_result);</FONT>
<BR><FONT SIZE=2 FACE="Arial"> printf ("<CENTER><B>%s</B></CENTER><BR>\n", ticket_result);</FONT>
<BR><FONT SIZE=2 FACE="Arial"> temp_rt_ticket_num = strtok (ticket_result," ");</FONT>
<BR><FONT SIZE=2 FACE="Arial"> temp_rt_ticket_num = strtok (NULL," ");</FONT>
<BR><FONT SIZE=2 FACE="Arial"> temp_rt_ticket_num = strtok (NULL," ");</FONT>
<BR><FONT SIZE=2 FACE="Arial"> sprintf (temp_rt_comment," Ticket #%s acknowledged by %s", temp_rt_ticket_num,current_authdata.username);</FONT></P>
<P><FONT SIZE=2 FACE="Arial"> sprintf (nagios_rt_comment, "%s %s", comment_data, temp_rt_comment);</FONT>
<BR><FONT SIZE=2 FACE="Arial"> snprintf(command_buffer,sizeof(command_buffer)-1,"[%lu] ACKNOWLEDGE_HOST_PROBLEM;%s;%d;%d;%d;%s;%s\n",current_time,host_name,(sticky_ack==TRUE)?ACKNOWLEDGEMENT_STICKY:ACKNOWLEDGEMENT_NORMAL,(send_notification==TRUE)?1:0,(persistent_comment==TRUE)?1:0,comment_author,nagios_rt_comment);</FONT></P>
<P><FONT SIZE=2 FACE="Arial"> }</FONT>
<BR><FONT SIZE=2 FACE="Arial"> else</FONT>
<BR><FONT SIZE=2 FACE="Arial"> {</FONT>
<BR><FONT SIZE=2 FACE="Arial"> snprintf(command_buffer,sizeof(command_buffer)-1,"[%lu] ACKNOWLEDGE_HOST_PROBLEM;%s;%d;%d;%d;%s;%s\n",current_time,host_name,(sticky_ack==TRUE)?ACKNOWLEDGEMENT_STICKY:ACKNOWLEDGEMENT_NORMAL,(send_notification==TRUE)?1:0,(persistent_comment==TRUE)?1:0,comment_author,comment_data);</FONT></P>
<P><FONT SIZE=2 FACE="Arial"> }</FONT>
<BR><FONT SIZE=2 FACE="Arial"> break;</FONT>
</P>
<BR>
<P><FONT SIZE=2 FACE="Arial">=====================================</FONT>
</P>
<P><FONT SIZE=2 FACE="Arial">Now for setting the do_make_ticket variable.</FONT>
</P>
<P><FONT SIZE=2 FACE="Arial">If you look in the process_cgivars function, you will see how Nagios gets the values of the acknowlegement form.</FONT>
</P>
<P><FONT SIZE=2 FACE="Arial">There is a large else statement that deals with all the various checkboxes. For example.</FONT>
</P>
<P><FONT SIZE=2 FACE="Arial"> /* we got the service check force option */</FONT>
<BR><FONT SIZE=2 FACE="Arial"> else if(!strcmp(variables[x],"force_check"))</FONT>
<BR><FONT SIZE=2 FACE="Arial"> force_check=TRUE;</FONT>
</P>
<P><FONT SIZE=2 FACE="Arial">I added my own check under the force option.</FONT>
</P>
<P><FONT SIZE=2 FACE="Arial"> /* for request tracker ticket making */</FONT>
<BR><FONT SIZE=2 FACE="Arial"> /* we got the service acknowledge do_make_ticket option */</FONT>
<BR><FONT SIZE=2 FACE="Arial"> else if(!strcmp(variables[x],"do_make_ticket"))</FONT>
<BR><FONT SIZE=2 FACE="Arial"> do_make_ticket=TRUE;</FONT>
</P>
<P><FONT SIZE=2 FACE="Arial">=========================================</FONT>
</P>
<P><FONT SIZE=2 FACE="Arial">Now for displaying the checkbox</FONT>
</P>
<P><FONT SIZE=2 FACE="Arial">Look in the request_command_data function.</FONT>
</P>
<P><FONT SIZE=2 FACE="Arial">Again there is a switch statement, you want to add your code to the CMD_ACKNOWLEDGE_HOST_PROBLEM and/or CMD_ACKNOWLEDGE_SVC_PROBLEM cases.</FONT></P>
<P> <FONT SIZE=2 FACE="Arial">/* these two lines are already there by default and display the "send_notification" checkbox. */</FONT>
<BR><FONT SIZE=2 FACE="Arial"> printf("<INPUT TYPE='checkbox' NAME='send_notification' CHECKED>");</FONT>
<BR><FONT SIZE=2 FACE="Arial"> printf("</b></td></tr>\n");</FONT>
<BR><FONT SIZE=2 FACE="Arial"> </FONT>
<BR> <FONT SIZE=2 FACE="Arial">/* I added these lines to add the create RT ticket checkbox</FONT>
<BR><FONT SIZE=2 FACE="Arial"> printf("<tr><td CLASS='optBoxItem'>Create RT Ticket:</td><td><b>");</FONT>
<BR><FONT SIZE=2 FACE="Arial"> printf("<INPUT TYPE='checkbox' NAME='do_make_ticket' CHECKED>");</FONT>
</P>
<P><FONT SIZE=2 FACE="Arial">==========================================</FONT>
</P>
<P><FONT SIZE=2 FACE="Arial">Remember to initialize do_make_ticket and any other variables at the top of cmd.c so you don't get compiler errors.</FONT>
</P>
<P><FONT SIZE=2 FACE="Arial">int do_make_ticket=FALSE;</FONT>
</P>
<P><FONT SIZE=2 FACE="Arial">==========================================</FONT>
</P>
<P><FONT SIZE=2 FACE="Arial">Some other things I have done to make this work smoothly is to make sure that the user name used to log into Nagios and RT are the same, as well as setting the user's primary smtp address to correspond as well. This is done because I want the person who acknowleges the ticket to be the person who is assigned the ticket in RT.</FONT></P>
<P><FONT SIZE=2 FACE="Arial">Hopefully, people will find this information useful and hopefully, someone else will take this code and refine it to use better c programming practices eliminate the, hard coding, lack of memory allocation, lack of exception handling and make this a more elegant solution. The above code isn't exactly what we use, since our RT and Nagios servers run on different machines and I have to deal with the problems caused by that. Also in the future I'll probably change this to use a custom CLI made with the RT perl api since I need to also handle custom fields.</FONT></P>
<P><FONT SIZE=2 FACE="Arial">If anyone knows of how to handle custom fields with the CLI, rather than using the perl api or even better has a C api for RT, I'd like to hear about it. </FONT></P>
</BODY>
</HTML>