Este post se parece mucho a uno anterior, el el cual utilizabamos Perl y SNMP para ver si una serie de procesos estaba muerto; Sin embargo en este caso lo que tenemos es un ‘watchdog’, un simple programa que es ejecutado cada cierto tiempoy si detecta que un programa en particular está caido, entonces trata de reiniciarlo.
La lógica es muy sencilla, revise si el servicio está siendo monitoreado por Net-SNMP (más fácil que hacer un ‘ps’ usted mismo, además de que es más flexible ya que usted puede controlar cuantas procesos es la cantidad correcta que deberían estarse ejecutando). Si la bandera es diferente de 0 es que hay un error, usted reinicia al demonio y manda una notificación por correo electrónico a su ‘helpdesk’. Para correr el programa periodicamente, deberá utilizar ‘cron’:
1:#!/usr/bin/perl
2:
3:use Net::SNMP;
4:use Net::SMTP;
5:use strict;
6:
7:# START USER CONFIGURABLE SECTION
8:use constant MAIL_SERVER => 'localhost';
9:use constant MAIL_SUBJECT => "[INFO $0]: A daemon was restarted automatically!";
10:use constant MAIL_FROM => 'angelnegro@domain.com';
11:use constant SNMP_COMMUNITY => 'public';
12:# END USER CONFIGURABLE SECTION
13:
14:use constant PORT => 161;
15:use constant BASE_OID => '.1.3.6.1.4.1.2021.2';
16:use constant INDEX_OID => BASE_OID . '.1.2';
17:use constant STATUS_OID => BASE_OID . '.1.100';
18:use constant VERSION => 2;
19:use constant UNKNOWN_INDEX => -1;
20:use constant DEFAULT_HOST => 'localhost';
21:use constant ERROR_CODE => 192;
22:use constant OK_CODE => 0;
23:use constant DEBUG => 0;
24:
25:if ((scalar(@ARGV)) != 3) {
26: die "Please provide the daemon name, restart command, and a destination email address!";
27:}
28:my $flag = OK_CODE;
29:my ($session, $error) = Net::SNMP->session(
30: -hostname => DEFAULT_HOST,
31: -community => SNMP_COMMUNITY,
32: -version => VERSION,
33: -port => PORT
34:);
35:if ($error) {
36: die "[ERROR $0]: $error";
37:}
38:my $result = $session->get_table(
39: -baseoid => INDEX_OID
40:);
41:if (! defined $result) {
42: printf "\t[ERROR $0]: No response from, %s\n", DEFAULT_HOST;
43: $flag = ERROR_CODE;
44:} else {
45: my $index = UNKNOWN_INDEX;
46: foreach my $key (keys %${result}) {
47: # Get the Index for the desired service. The key index
48: # will depend of the order given by the SA, so it is better
49: # to look for it!
50: if ($$result{$key} eq "$ARGV[0]") {
51: my @tokens = split('\.', $key);
52: $index = $tokens[scalar(@tokens)-1];
53: }
54: }
55: # It is being monitored?
56: if ($index == UNKNOWN_INDEX) {
57: print "\t[INFO $0]: Daemon not being monitored!\n";
58: $flag = ERROR_CODE;
59: } else {
60: # Now get the status of the daemon, according to SNMP!
61: my $key = STATUS_OID . "\.$index";
62: my $result2 = $session->get_request(
63: -varbindlist => [$key]
64: );
65: if (! defined $result2) {
66: my $error_message = $session->error;
67: printf "\t[ERROR $0]: %s, %s\n", $ARGV[0], $error;
68: $flag = ERROR_CODE;
69: } elsif ($$result2{$key} != 0) {
70: printf "[WARNING $0]: %s, status=%s\n", $ARGV[0], $$result2{$key};
71: printf "[INFO $0]: Executing: %s\n", $ARGV[1];
72: my $output=`$ARGV[1] 2>&1`;
73: my $exit_code = $?;
74: my $smtp = Net::SMTP->new(
75: MAIL_SERVER,
76: Timeout => 20,
77: Debug => DEBUG
78: );
79: $smtp->mail(MAIL_FROM);
80: $smtp->to($ARGV[2]);
81: $smtp->data();
82: $smtp->datasend("To: " . $ARGV[2] . "\n");
83: $smtp->datasend("Subject: " . MAIL_SUBJECT . ": $ARGV[0]\n");
84: $smtp->datasend("\n");
85: $smtp->datasend("Command executed to restart the daemon:");
86: $smtp->datasend("\n");
87: $smtp->datasend($ARGV[1]);
88: $smtp->datasend("\n");
89: $smtp->datasend("Command output:");
90: $smtp->datasend("\n");
91: $smtp->datasend($output);
92: $smtp->datasend("\n");
93: $smtp->datasend("Exit code: $exit_code");
94: $smtp->dataend();
95: $smtp->quit;
96: }
97: }
98:}
99:my $error_message = $session->error;
100:if ($error) {
101: printf "\t[ERROR $0]: %s, %s\n", $ARGV[0], $error;
102: $flag = ERROR_CODE;
103:}
104:if (defined $session) {
105: $session->close;
106:}
107:exit $flag;
108:
109:__END__
110:
111:=head1 NAME
112:
113:SimpleWatchDog.plx - A program used to restart daemons if the fail.
114:
115:=head1 DESCRIPTION
116:
117:This program is meant to be executed from cron in order to check the status of a givem program.
118:It is expected than the daemon to check runs in the same machine where this program runs.
119:
120:=head2 CONFIGURATION
121:
122:=over4
123:
124:=item Identify which process name to put on the /etc/snmp/snmpd.conf file
125:
126:ps -e|perl -p -i -e' $_ =~ s# {1,}# #g; $_ =~ s# #|#g;'|cut -f5 -d'|'|sort|grep -v CMD|grep myprogram
127:
128:=item * Modify the 'snmpd.conf' file
129:
130:proc myprogram 1 1
131:
132:=item * Restart SNMPD
133:
134:service restart snmpd
135:
136:=item * Modify this script
137:
138:Modify the variables: MAIL_SERVER, MAIL_SUBJECT, SNMP_COMMUNITY
139:
140:=back
141:
142:=head2 HOW TO RUN
143:
144:Put an entry like this on cron:
145:
146: # Keep an eye on the daemon 'myprogram', every 10 minutes
147: */10 * * * * /opt/SimpleWatchDog.plx myprogram /etc/init.d/mypgrogram restart josevnz@domain.com > /var/log/myprogram-watchdog.log 2>&1
148:
149:=head1 AUTHOR
150:
151:Jose V Nunez Zuleta
152:
153:=head1 BLOG
154:
155:El Angel Negro - http://elangelnegro.blogspot.com
156:
157:=head1 LICENSE
158:
159:GPL
160:
161:=head1 VERSION
162:
163:0.1 - 02/27/2005
164:
165:=cut
El crontab para nuestro programa:
# Watchdog for the program smartd
*/10 * * * * /usr/local/sysadmin/SimpleWatchDog.plx NBScpCopier.pl “/etc/init.d/smartd restart” angelnegro@domain.com > /var/log/smartd-watchdog.log 2>&1
Aqui está el código por si quiere bajarse el programita.