### ### Copyright 2000-2007 University of Illinois Board of Trustees ### All rights reserved. ### ### swatch.pm - swatch module for psgconf ### ### Campus Information Technologies and Educational Services ### University of Illinois at Urbana-Champaign ### package PSGConf::Control::swatch; use strict; use PSGConf::Action::GenerateFile::Literal; use PSGConf::Data::Boolean; use PSGConf::Data::List; use PSGConf::Data::String; use PSGConf::Control::Packages qw(_add_pkgs); ############################################################################### ### policy methods ############################################################################### ### ### WARNING: Needs to be called after syslog_default_dir policy is called, ### because syslog_dir may get prepended there. ### sub _policy_add_crontab { my ($self, $psgconf) = @_; my ($cmd); return if ( ! -f $psgconf->data_obj('swatch_cmd')->get() || $psgconf->data_obj('swatch_enable')->equals('false')); $cmd = $psgconf->data_obj('swatch_cmd')->get() . ' -c /usr/local/etc/swatchrc -f ' . $psgconf->data_obj('syslog_dir')->get() . '/messages > /dev/null 2>&1'; $psgconf->data_obj('crontabs')->insert( {'root' => [{ hour => $psgconf->data_obj('swatch_hour')->get(), minute => $psgconf->data_obj('swatch_minute')->get(), command => $cmd }] } ); } ### ### WARNING: This is a fix because Solaris systems complain about a host ### being our address, when you look into the MAC address it reports, that ### is the same host's MAC address. ### sub _policy_add_swatch_rule { my ($self, $psgconf) = @_; my (@mac, @ip, $i, @res, $line, $tmp); ### If we are not running swatch nor on Solaris, just return return if ( ! $psgconf->data_obj('platform')->match('solaris') || $psgconf->data_obj('swatch_enable')->equals('false')); ### find all the IP/MAC pairs that we are currently using $i=-1; @res = `/sbin/ifconfig -au`; foreach $line ( @res ) { if ( $line =~ /^\s+inet / ) { $i++; $tmp=$line; $tmp =~ s/^\s*inet //; $tmp =~ s/\s.*$//; $ip[$i] = &_format_addr($tmp, 'IP'); } if ( $line =~ /^\s+ether / ) { my ($tmp) = $line; $tmp =~ s/^\s*ether //; $mac[$i] = &_format_addr($tmp, 'MAC'); } } ### Now assemble the swatch configuration for all the IP/MAC pairs $line=undef; for ($i = 0; $i < scalar (@ip); $i++) { $line .= "ignore / WARNING: IP: Hardware address " . $mac[$i] . " trying to be our address " . $ip[$i] . "!/\n" if ( defined $ip[$i] && defined $mac[$i] ); } $psgconf->data_obj('swatch_config')->add( "# Ignore warnings reported between my IP and MAC address\n" . $line . " continue" ) if ( defined $line ); } sub _format_addr { my ($str, $type) = @_; my ($res, @addr, $sep, $cnt, $t, $digits); if ( $type eq 'IP' ) { $sep = '.'; $cnt = 4; $digits = 3; $t = 'd'; } elsif ( $type eq 'MAC' ) { $sep = ':'; $cnt = 6; $digits = 2; $t = 'x'; } else { return undef; } @addr = split (/\Q$sep\E/, $str); return undef if ( $cnt != scalar (@addr) ); $res = undef; for (my $i = 0; $i < scalar (@addr); $i++) { $res .= $sep if ( defined $res ); $res .= sprintf "%${digits}.${digits}$t", ($type eq 'MAC') ? hex($addr[$i]) : $addr[$i]; } return $res; }; ############################################################################### ### Constructor ############################################################################### sub new { my ($class, $psgconf) = @_; my ($self); $self = {}; bless($self, $class); $self->{name} = 'swatch'; $self->{enable} = $self->{name} . '_enable'; $self->{packages} = $self->{name} . '_packages'; $psgconf->register_data( swatch_enable => PSGConf::Data::Boolean->new( value => 'false' ), swatch_config => PSGConf::Data::List->new(), swatch_cmd => PSGConf::Data::String->new( 'value_abspath' => 1, value => '/usr/local/bin/swatch' ), swatch_mailto => PSGConf::Data::String->new( value => 'root' ), swatch_hour => PSGConf::Data::String->new( value => '23' ), swatch_minute => PSGConf::Data::String->new( value => '58' ), swatch_packages => PSGConf::Data::List->new() ); $psgconf->register_policy($self, swatch_add_packages => '_add_pkgs', swatch_add_crontab => '_policy_add_crontab', swatch_add_rule => '_policy_add_swatch_rule' ); return $self; } ############################################################################## ### decide() method ############################################################################### sub decide { my ($self, $psgconf) = @_; return if ($psgconf->data_obj('swatch_enable')->equals('false')); $psgconf->register_actions( PSGConf::Action::GenerateFile::Literal->new( name => '/usr/local/etc/swatchrc', mode => 0640, description => 'Swatch Configuration File', content => join ("\n\n", @{$psgconf->data_obj('swatch_config')->get()}) . "\n\nwatchfor /.*/\n\tmail addresses=" . $psgconf->data_obj('swatch_mailto')->get() . ",subject=Message from Swatch on " . $psgconf->data_obj('hostname')->get() . ",keep_open=1\n" ) ); } ############################################################################### ### documentation ############################################################################### 1; __END__ =head1 NAME PSGConf::Control::swatch - psgconf control class for swatch syslog reporting =head1 SYNOPSIS In F: Control PSGConf::Control::swatch =head1 DESCRIPTION The B module provides a B control object for configuring swatch syslog reporting. It supports the following methods: =over 4 =item new() The constructor. Its parameter is a reference to the B object. It registers the following data objects: =over 4 =item I A B object, indicating whether swatch should be configured. The default is no. =item I A B object containing a list of packages to install. =item I A B object containing a list of swatch actions to put into the F file. =item I A B object containing an email address to send the results of the C command to. =item I A B object containing the full command to the F binary. Defaults to F. =item I A B object containing which hour or hours to run F. Defaults to C<23>. =item I A B object containing which minute or minutes to run F. Defaults to C<58>. =back The constructor also registers the following policy methods: =over 4 =item I If I is true, adds the B package and its requirements to the I Data object (provided by B). =item I If I is true, adds an entry for the I nightly to I's I Data object (provided by B). =item decide() Does the following: If I is true, creates the F config file for the C command to use. =back =back =head1 SEE ALSO L L L L L L L L L =cut