Nagios and RT Integration

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.

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.

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?

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
(/sbin).

This is what you need to do …

  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.

  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.

  3. Add logic to both the service and host alarm acknowlegement code to run
    make_ticket when either service or host problems are acknowleged.

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.

int make_ticket (char * owner, char * subject, char * result)
{
char rt_command[300];
FILE * temp_pipe;
char requestor[40];
sprintf (requestor, “%s@mycompany.com”, owner);

    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);

    /* Create the ticket */ 
    temp_pipe = popen(rt_command,"r"); 
    if (!temp_pipe) 
    { 
            result = "Failed to create Ticket"; 
    } 
    else 
    { 
            fgets(result, 300, temp_pipe); 
            sprintf (result, "%s", result); 
    } 

}

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.

    case CMD_ACKNOWLEDGE_HOST_PROBLEM: 
            if (do_make_ticket) 
            { 
                    /* create a ticket in request tracker */ 
                    sprintf (subject, "Alarm for %s", host_name); 
                    sprintf (rt_comment, "%s", comment_data); 
                    make_ticket (current_authdata.username,subject,

rt_comment, ticket_result);
printf ("%s
\n",
ticket_result);
temp_rt_ticket_num = strtok (ticket_result," “);
temp_rt_ticket_num = strtok (NULL,” “);
temp_rt_ticket_num = strtok (NULL,” “);
sprintf (temp_rt_comment,” Ticket #%s acknowledged
by %s", temp_rt_ticket_num,current_authdata.username);

                    sprintf (nagios_rt_comment, "%s %s", comment_data,

temp_rt_comment);

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)
;

            } 
            else 
            { 
            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);

            } 
            break; 

Now for setting the do_make_ticket variable.

If you look in the process_cgivars function, you will see how Nagios gets
the values of the acknowlegement form.

There is a large else statement that deals with all the various checkboxes.
For example.

            /* we got the service check force option */ 
            else if(!strcmp(variables[x],"force_check")) 
                    force_check=TRUE; 

I added my own check under the force option.

            /* for request tracker ticket making */ 
            /* we got the service acknowledge do_make_ticket option */ 
            else if(!strcmp(variables[x],"do_make_ticket")) 
                    do_make_ticket=TRUE; 

Now for displaying the checkbox

Look in the request_command_data function.

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.

            /* these two lines are already there by default and display

the “send_notification” checkbox. */
printf("");
printf("\n");

            /* I added these lines to add the create RT ticket checkbox 
                   printf("<tr><td CLASS='optBoxItem'>Create RT

Ticket:

");
printf("");

Remember to initialize do_make_ticket and any other variables at the top of
cmd.c so you don’t get compiler errors.

int do_make_ticket=FALSE;

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.

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.

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.

Hi all,
I am kindoff new to the RT system so any suggestions for the following
questions will be really helpful.

1.There is the Tickets table and it has dates “start” ,“started” and
"created " date. What is the difference between the three.

  1. In our system RT installed and it works fine, problem is when a ticket
    is “open” the resolved date is 1/1/1970. When the ticket is resolved, the
    resolved date is set to the time and date when it was resolved. What is
    happening in our system is that this resolved date is set to 1/1/1970
    especially for new users. IS there some condition somewhere which is doing
    this.

Regards,
Ahalya Nathan
Senior Programmer / Analyst
Information Technology, Metropolitan Utilities District
(402) 449-8218 phone
(402) 449-8131 fax
ahalya_nathan@mudnebr.com

Hello,

i tryed to implement the Hack from Evan into the C Source of then Nagios
cmd.c File described in the Thread

I have only a little knowledge of C , so i became a compiler Error.

gcc -g -O2 -DHAVE_CONFIG_H -DNSCGI -o cmd.cgi cmd.c extcmd_list.o
getcgi.o cgiutils.o cgiauth.o macros-cgi.o skiplist.o objects-cgi.o
xobjects-cgi.o statusdata-cgi.o xstatusdata-cgi.o comments-cgi.o
downtime-cgi.o
cmd.c: In function ?make_ticket?:
cmd.c:325: error: lvalue required as left operand of assignment
cmd.c:329: warning: passing argument 1 of ?fgets? from incompatible
pointer type
cmd.c:330: warning: passing argument 1 of ?sprintf? from incompatible
pointer type
cmd.c: In function ?request_command_data?:
cmd.c:1031: warning: passing argument 1 of ?sprintf? from incompatible
pointer type
cmd.c:1032: warning: passing argument 1 of ?sprintf? from incompatible
pointer type
cmd.c:1033: warning: passing argument 2 of ?make_ticket? from incompatible
pointer type
cmd.c:1033: warning: passing argument 3 of ?make_ticket? from incompatible
pointer type
cmd.c:1033: warning: passing argument 4 of ?make_ticket? from incompatible
pointer type
cmd.c:1035: warning: passing argument 1 of ?strtok? from incompatible
pointer type
cmd.c:1035: error: lvalue required as left operand of assignment
cmd.c:1036: error: lvalue required as left operand of assignment
cmd.c:1037: error: lvalue required as left operand of assignment
cmd.c:1038: warning: passing argument 1 of ?sprintf? from incompatible
pointer type
cmd.c:1039: warning: passing argument 1 of ?sprintf? from incompatible
pointer type
cmd.c:1040: warning: passing argument 1 of ?snprintf? from incompatible
pointer type
cmd.c:1044: warning: passing argument 1 of ?snprintf? from incompatible
pointer type

Have anyone a correct cmd.c file for me, or have any suggestions ?

Following Lines are added to the cmd.c file :

104 int subject(char *);
105 int rt_comment(char *);
106 int temp_rt_ticket_num(char *);
107 int temp_rt_comment(char *);
108 int nagios_rt_comment(char *);
109 int temp_rt_ticket_num(char *);
110 int command_buffer(char *);
111 int current_time(char *);
112 int ticket_result(char *);
113 int result(char *);

311 int make_ticket(char * username, char * subject, char * rt_comment,
char * ticket_result)
312
313 {
314 char rt_command[300];
315 char owner[100];
316 FILE * temp_pipe;
317 char requestor[40];
318 sprintf (requestor, “%s [at] mycompany”, owner);
319 sprintf (rt_command,“/opt/rt3/bin/rt create -t ticket set status=new
subject=‘%s’ owner=‘%s’ queue=‘Alarms’ requestors=‘%s’ adm
incc=‘supervisor [at] mycompany’ priority=‘99’”,
subject,owner,requestor);
320
321 /* Create the ticket */
322 temp_pipe = popen(rt_command,“r”);
323 if (!temp_pipe)
324 {
325 result = “Failed to create Ticket”;
326 }
327 else
328 {
329 fgets(result, 300, temp_pipe);
330 sprintf (result, “%s”, result);
331 }
332 }

1027
1028 if (do_make_ticket)
1029 {
1030 /* create a ticket in request tracker */
1031 sprintf (subject, “Alarm for %s”, host_name);
1032 sprintf (rt_comment, “%s”, comment_data);
1033 make_ticket (current_authdata.username,subject,rt_comment,
ticket_result);
1034 printf (“%s
\n”,ticket_result);
1035 temp_rt_ticket_num = strtok (ticket_result," “);
1036 temp_rt_ticket_num = strtok (NULL,” “);
1037 temp_rt_ticket_num = strtok (NULL,” “);
1038 sprintf (temp_rt_comment,” Ticket #%s acknowledged by %s",
temp_rt_ticket_num,current_authdata.username);
1039 sprintf (nagios_rt_comment, “%s %s”, comment_data,temp_rt_comment);
1040
snprintf(command_buffer,sizeof(command_buffer)-1,“[%lu]ACKNOWLEDGE_HOST_PROBLEM;%s;%d;%d;%d;%s;%s\n”,current_time,host_name,(st

icky_ack==TRUE)?ACKNOWLEDGEMENT_STICKY:ACKNOWLEDGEMENT_NORMAL,(send_notification==TRUE)?1:0,(persistent_comment==TRUE)?1:0,comm
ent_author,nagios_rt_comment);
1041 }
1042 else
1043 {
1044
snprintf(command_buffer,sizeof(command_buffer)-1,“[%lu]ACKNOWLEDGE_HOST_PROBLEM;%s;%d;%d;%d;%s;%s\n”,current_time,host_name,(st

icky_ack==TRUE)?ACKNOWLEDGEMENT_STICKY:ACKNOWLEDGEMENT_NORMAL,(send_notification==TRUE)?1:0,(persistent_comment==TRUE)?1:0,comm
ent_author,comment_data);
1045 }
1046 break;
1047

Thank you

Greetings from Germany
Ingo von Itter

Geschäftsführer: Rolf Herzog, Thomas Benk
AGES Maut System GmbH & Co. KG
AG Düsseldorf HRA 14045, USt-IdNr.: DE 202525868
AGES International GmbH & Co. KG
AG Düsseldorf HRA 16636, USt-IdNr.: DE 813749831
AGES ETS GmbH
AG Düsseldorf HRB 55580, USt-IdNr.: DE 814789134

Hello,

i tryed to implement the Hack from Evan into the C Source of then Nagios cmd.c File described
in the Thread Carbon60: Managed Cloud Services

Have you seen

It may be easier to try if you don’t have C knowledge.

-kevin