Previous Up Next

5  PICA Framework for Integrated Alarms (PIFIA)

The design of the PIFIA floats around the following concepts:
  1. Flexibility
  2. 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.


Previous Up Next