Finding Core Perl Modules

I wasted 15 minutes the other day trying to remember how to do this, so here it is for the future: to find out if and when a perl module got added to the core, you want Richard Clamp's excellent Module::CoreList.

Recent versions have a 'corelist' frontend command, so I typically use that e.g.

$ corelist File::Basename
File::Basename  was first released with perl 5

$ corelist warnings
warnings  was first released with perl 5.006

$ corelist /^File::Spec/
File::Spec  was first released with perl 5.00405
File::Spec::Cygwin  was first released with perl 5.006002
File::Spec::Epoc  was first released with perl 5.006001
File::Spec::Functions  was first released with perl 5.00504
File::Spec::Mac  was first released with perl 5.00405
File::Spec::OS2  was first released with perl 5.00405
File::Spec::Unix  was first released with perl 5.00405
File::Spec::VMS  was first released with perl 5.00405
File::Spec::Win32  was first released with perl 5.00405

$ corelist URI::Escape
URI::Escape  was not in CORE (or so I think)

Blosxom4Nagios

A little whole ago at one of my client sites we decided that we wanted to monitor the bulk of our Nagios notifications via RSS rather than via email or jabber. The centralised river-of-news architecture of RSS is just a much better fit for high-volume notification flow than the individual silos and persistent messaging nature of email.

There are a few nice RSS solutions out there for Nagios, including the following:

We quite liked Altinity's RSS4NAGIOS because it was notifications (rather than alerts) based, and because it was pretty easy to just drop in and use. The only thing we didn't really like was that it was still relatively static - it provides nice per-user feeds, but you can't carve those feeds up or drill down to subsets of the data very easily. We wanted to be able to slice-and-dice things a bit more dynamically - be able to look at feeds for per-host, per-hostgroup, per-status, or date-filtered notifications, for example.

I'm also a blosxom developer, so I quickly realised that I could do everything I wanted pretty trivially using blosxom. All I needed was a script to capture and tag notifications as blosxom posts, and then I could have dynamic filtering, multi-dimensional tag-based feeds, etc., all pretty much for free.

So a couple of afternoons later, Blosxom4Nagios was up and running. It's basically a single-purpose blosxom install that you drop into a directory somewhere (/var/log/nagios/blosxom, by default), hook into apache for display, hook into nagios to accept notifications, and away you go.

Notifications are tagged by type (host/service), state (OK, WARNING, CRITICAL etc.), hostname, hostgroup, service name, service group, contact, and date, so you can filter notifications based on any of these, and produce feeds (both RSS2 and atom) on any of them as well e.g.

  • http://www.example.com/nagios/blosxom/tags/nagiosadmin
  • http://www.example.com/nagios/blosxom/tags/hostgroup1/rss
  • http://www.example.com/nagios/blosxom/tags/myhost/atom
  • http://www.example.com/nagios/blosxom/tags/servicegroup2
  • http://www.example.com/nagios/blosxom/tags/randomservice
  • http://www.example.com/nagios/blosxom/tags/CRITICAL/atom
  • http://www.example.com/nagios/blosxom/2008/03/tags/nagiosadmin
  • http://www.example.com/nagios/blosxom/2008/03/19/tags/myhost/rss

etc.

Screenshots:

Default View

Filtering by date

Filtering by host

Blosxom4Nagios is available here:

and is licensed under the same MIT Licence as blosxom itself.

Comments and feedback welcome.

Comparing Directories

Saw this post fly past in the twitter stream today: http://linuxshellaccount.blogspot.com/2008/03/perl-directory-permissions-difference.html. It's a script by Mike Golvach to do something like a diff -r, but also showing differences in permissions and ownership, rather than just content.

I've written a CPAN module to do stuff like this - File::DirCompare - so thought I'd check how straightforward this would be using File::DirCompare:

#!/usr/bin/perl

use strict;
use File::Basename;
use File::DirCompare;
use File::Compare qw(compare);
use File::stat;

die "Usage: " . basename($0) . " dir1 dir2\n" unless @ARGV == 2;

my ($dir1, $dir2) = @ARGV;

File::DirCompare->compare($dir1, $dir2, sub {
  my ($a, $b) = @_;
  if (! $b) {
    printf "Only in %s: %s\n", dirname($a), basename($a);
  } elsif (! $a) {
    printf "Only in %s: %s\n", dirname($b), basename($b);
  } else {
    my $stata = stat $a;
    my $statb = stat $b;

    # Return unless different
    return unless compare($a, $b) != 0 || 
      $stata->mode != $statb->mode ||
      $stata->uid  != $statb->uid  ||   
      $stata->gid  != $statb->gid;

    # Report
    printf "%04o %s %s %s\t\t%04o %s %s %s\n", 
      $stata->mode & 07777, basename($a), 
        (getpwuid($stata->uid))[0], (getgrgid($stata->gid))[0],
      $statb->mode & 07777, basename($b), 
        (getpwuid($statb->uid))[0], (getgrgid($statb->gid))[0];
  }
}, { ignore_cmp => 1 });

So this reports all entries that are different in content or permissions or ownership e.g. given a tree like this (slightly modified from Mike's example):

$ ls -lR scripts1 scripts2
scripts1:
total 28
-rw-r--r-- 1 gavin gavin 0 Mar 17 16:41 script1
-rw-r--r-- 1 gavin gavin 0 Mar 17 16:41 script1.bak
-rw-r--r-- 1 gavin gavin 0 Mar 17 16:41 script2
-rw-r--r-- 1 gavin gavin 0 Mar 17 16:41 script2.bak
-rw-r--r-- 1 gavin gavin 0 Mar 17 16:41 script3
-rw-r--r-- 1 gavin gavin 0 Mar 17 16:41 script3.bak
-rw-r--r-- 1 gavin gavin 0 Mar 17 16:49 script4
scripts2:
total 28
-rw-r--r-- 1 gavin users 0 Mar 17 16:41 script1
-rw-r--r-- 1 gavin users 0 Mar 17 16:41 script1.bak
-rw-r--r-- 1 gavin gavin 0 Mar 17 16:41 script2
-rw-r--r-- 1 gavin gavin 0 Mar 17 16:41 script2.bak
-rwxr-xr-x 1 gavin gavin 0 Mar 17 16:41 script3*
-rwxr-xr-x 1 gavin gavin 0 Mar 17 16:41 script3.bak*
-rw-r--r-- 1 gavin gavin 0 Mar 17 16:49 script5

it will give output like the following:

$ ./pdiff2 scripts1 scripts2
0644 script1 gavin gavin                0644 script1 gavin users
0644 script1.bak gavin gavin            0644 script1.bak gavin users
0644 script3 gavin gavin                0755 script3 gavin gavin
0644 script3.bak gavin gavin            0755 script3.bak gavin gavin
Only in scripts1: script4
Only in scripts2: script5

This obviously has dependencies that Mike's version doesn't have, but it comes out much shorter and clearer, I think. It also doesn't fork and parse an external ls, so it should be more portable and less fragile. I should probably be caching the getpwuid lookups too, but that would have made it 5 lines longer. ;-)

Random Tweet #4

Nice w3schools page on html latin-1 entities: http://www.w3schools.com/tags/ref_entities.asp.

Paying Bills

Was thinking in the weekend about places where I waste time, areas of inefficiency in my extremely well-ordered life (cough splutter).

One of the more obvious was bill handling. I receive paper bills during the month from the likes of Energy Australia, Sydney Water, David Jones, our local council for rates, etc. These all go into a pending file in the filing cabinet, in date order, and I then periodically check that file during the month and pay any bills that are coming due. If I get busy or forgetful I may miss a due date and pay a bill late. If a bill gets lost in the post I may not pay it at all. And the process is all dependent on me polling my billing file at some reasonable frequency.

There are variants to this process too. Some of my friends do all their bills once a month, and just queue the payments in their bank accounts for future payment on or near the due date. That's a lower workload system than mine, but for some (mostly illogical) reason I find myself not really trusting future-dated bill payments in the same way as immediate ones.

There's also a free (for users) service available in Australia called BPay View which allows you to receive your bills electronically directly into your internet banking account, and pay them from there. This is nice in that it removes the paper and data entry pieces of the problem, but it's still a pull model - I still have to remember to check the BPay View page periodically - and it's limited to vendors that have signed up for the program.

As I see it, there are two main areas of friction in this process:

  1. using a pull model i.e. the process all being dependent on me remembering to check my bill status periodically and pay those that are coming due. My mental world is quite cluttered enough without having to remember administrivia like bills.

  2. the automation friction around paper-based or PDF-based bills, and the consequent data entry requirements, the scope for user errors, etc.

BPay View mostly solves the second of these, but it's a solution that's closely coupled with your Internet Banking provider. This has security benefits, but it also limits you to your Internet Banking platform. For me, the first of these is a bigger issue, so I'd probably prefer a solution that was decoupled from my internet banking, and accept a few more issues with #2.

So here's what I want:

  • a billing service that receives bills from vendors on my behalf and enters them into its system. Ideally this is via email (or even a web service) and an XML bill attachment; in the real world it probably still involves paper bills and data entry for the short to medium term.

  • a flexible notification system that pushes alerts to me when bills are due based on per-vendor criteria I configure. This should include at least options like email, IM, SMS, twitter, etc. Notifications could be fire-once or fire-until-acknowledged, as the user chooses.

  • for bonus points, an easy method of transferring bills into my internet banking. The dumb solution is probably just a per-bill view from which I can cut and paste fields; smarter solutions would be great, but are probably dependent on the internet banking side. Or maybe we do some kind of per-vendor pay online magic, if it's possible to figure out the security side of not storing credit card info. Hmmm.

That sounds pretty tractable. Anyone know anything like this?

Random Tweet #3

Nice recent blog summary of free chart/graph solutions: http://tutorialblog.org/free-chart-and-graph-solutions/.

Random Tweet #2

Twitter2blosxom script seems to be working nicely - one more test before bed.

Random Tweet #1

Testing twitter to blosxom script.

Finding/Delete Broken Symlinks

Find goodness (with a recent-ish find for the '-delete'):

find -L . -type l
find -L . -type l -delete