5 PICA Framework for Integrated Alarms (PIFIA)
The design of the PIFIA floats around the following concepts:
-
Flexibility
- Simplicity
Alarms are a special type of object: we will normally want to execute it and
it can depend on some files (regular files, not other alarms). So, it needs one
more attribute (priority), has an additional optional attribute, and a
special additional environment to support dependencies. But, as the rest of
the objects, it's installed in the appropriate hosts, so we will always have
the possibility of execute any alarm by hand, even if the ``central'' host is
down or unreachable.
The basic idea is that there is a program, the scheduler, that
is executed by cron (a pifia.cron file is in the PIFIA
distribution). Each time it's run, it looks for alarm scripts to be
executed...and executes them. Alarms have a priority, that defines
in which directory will they reside. This lets the scheduler treat at
different time intervals (defined in pifia.cron, of course) alarms of
different priorities. By default, the defined priorities are:
-
Emergency
- Every 10 minutes.
- Urgent
- Every 2 hours.
- Warning
- Once a day.
5.1 Directories and caller scripts
By default, alarms are searched in $picasrc/alarms, but you can specify
an absolute path to override this. They get installed in $picaalarms/priority in the remote machine. Because one can pass arbitrary (yes, we love that word) parameters to the alarm, it's not called directly, but
through a script, called ``alarmname-picacaller''. This also lets
us use scripts not designed originally for PICA. The only thing one needs is
to define the calling convention (it's one of the alarm optional attributes).
In its definition we can take advantage of the many features of the
preprocessor, as variable substitution or Perl on-the-fly code generation. It
describes the parameters the alarm will be called with. For example, we could
define an alarm like this:
alarm DNSChkUrgent {
priority = 'Urgent';
source = 'DNSChk';
perms = '755';
calling-convention = '-w 1 -c $threshold';
vars {
threshold = 8;
}
}
Supposing $picaalarms points to /var/lib/pica/alarms, DNSChkUrgent would get installed in
-rwxr-xr-x zoso zoso /var/lib/pica/alarms/Urgent/DNSChkUrgent
(note that we haven't specified any uid or gid) and the contents of
DNSChkUrgent-picacaller would be this:
#!/bin/sh
/var/lib/pica/alarms/Urgent/DNSChkUrgent -w 1 -c 8 "$@"
Cool, uh? The last "$@" lets you add more parameters if you want to
call it by hand.
5.2 The scheduler
We have a ``scheduler'' script that is run periodically from crond. The
cron file is looks more or less like this (I probably won't bother
changing this every time I change that file):
##
## PIFIA crontab entry
## From this crontab entry we will run the PIFIA scheduler periodically for
## each priority
##
# Emergency (every 10 minutes)
*/10 * * * * root <#$picabin#>/scheduler Emergency
# Urgent (every 2 hours)
15 */2 * * * root <#$picabin#>/scheduler Urgent
# Warning (once a day)
20 1 * * * root <#$picabin#>/scheduler Warning
Cron runs the scheduler for every priority, and the scheduler runs every
alarm in a given priority, using the -picacaller file, gets every alarm
output and generates a report that is sent via e-mail (or whatever command you
specify). Right now each alarm has to manage it's own variable persistency.
All of this will be solved as the time goes by, by the PIFIA lib.
5.3 The PIFIA Perl package
By now you should have realized that we like Perl and we have used it
throughout PICA. Well, for better integration with the program, the alarms are
also written in Perl, of course, and the facilities are a bunch of Perl subs in a package. As you have probably guessed, the package is pifia, and is distributed with PICA (no recursive dependency here, no alarms
are used to install a file).
The most important feature of the alarms package is the environment
perseval (persistent eval, it's not that we like Arturic
legends and we can't write the name of the knight of Galles). It looks
like this:
perseval {
if ($lastnotify - time() > $timebetweennots &&
some_other_condition()) {
print "Heck, some other condition, and I haven't notified you since ",
"$lastnotify\n";
}
@down = check_hosts();
foreach my $host (@down) {
print "New host down: $host" unless grep { $_ eq $host }
@downhosts;
}
$attrs{'something'} = calculate_something();
} preserve '$lastnotify', '@downhosts', '%attrs';
As you've probably noticed here, the perseval environment lets you write
code with persistent variables. Those are specified in the preserve
clause, after the program. Run the program, check whatever you want, and the
variables you specify will have the same value the had the last time you ran
the program. Really useful. All of this is implemented with the MLDBM package,
so you need it installed in your system for this this to work.