363 lines
10 KiB
Perl
363 lines
10 KiB
Perl
#!/usr/bin/env perl
|
|
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
|
|
package xCAT::NotifHandler;
|
|
BEGIN
|
|
{
|
|
$::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : -d '/opt/xcat' ? '/opt/xcat' : '/usr';
|
|
}
|
|
use lib "$::XCATROOT/lib/perl";
|
|
|
|
use File::Basename qw(fileparse);
|
|
use xCAT::Utils;
|
|
use Data::Dumper;
|
|
|
|
#%notif is a cache that holds the info from the "notification" table.
|
|
#the format of it is:
|
|
# {tablename=>{'a'=>[filename,...]
|
|
# 'u'=>[filename,,..]
|
|
# 'd'=>[filename,...]
|
|
# }
|
|
# }
|
|
my %notif;
|
|
my $masterpid;
|
|
my $dbworkerid;
|
|
|
|
1;
|
|
|
|
#-------------------------------------------------------------------------------
|
|
=head1 xCATi::NotifHandler
|
|
=head2 Package Description
|
|
This mondule caches the notification table and tracks the changes of it.
|
|
It also handles the event notification when xCAT database changes.
|
|
=cut
|
|
#-------------------------------------------------------------------------------
|
|
|
|
|
|
#--------------------------------------------------------------------------------
|
|
=head3 setup
|
|
It is called by xcatd to get set the pid of the parent of all this object.
|
|
Setup the signal to trap any changes in the notification table. It also
|
|
initializes the cache with the current data in the notification table.
|
|
table and store it into %notif variable.
|
|
Arguments:
|
|
pid -- the process id of the caller.
|
|
pid1 -- the process id of the dbworker.
|
|
Returns:
|
|
none
|
|
=cut
|
|
#-------------------------------------------------------------------------------
|
|
sub setup
|
|
{
|
|
$masterpid=shift;
|
|
if ($masterpid =~ /xCAT::NotifHandler/) {
|
|
$masterpid=shift;
|
|
}
|
|
$dbworkerid=shift;
|
|
|
|
refreshNotification();
|
|
|
|
$SIG{USR1}=\&handleNotifSignal;
|
|
}
|
|
|
|
#--------------------------------------------------------------------------------
|
|
=head3 handleNotifSignal
|
|
It is called when the signal is received. It then update the cache with the
|
|
latest data in the notification table.
|
|
Arguments:
|
|
none.
|
|
Returns:
|
|
none
|
|
=cut
|
|
#-------------------------------------------------------------------------------
|
|
sub handleNotifSignal {
|
|
#print "handleNotifSignal pid=$$\n";
|
|
refreshNotification();
|
|
$SIG{USR1}=\&handleNotifSignal;
|
|
}
|
|
|
|
#--------------------------------------------------------------------------------
|
|
=head3 sendNotifSignal
|
|
It is called by any module that has made changes to the notification table.
|
|
Arguments:
|
|
none.
|
|
Returns:
|
|
none
|
|
=cut
|
|
#-------------------------------------------------------------------------------
|
|
sub sendNotifSignal {
|
|
if ($masterpid) {
|
|
kill('USR1', $masterpid);
|
|
}
|
|
if ($dbworkerid) {
|
|
kill('USR1', $dbworkerid);
|
|
}
|
|
}
|
|
|
|
|
|
#--------------------------------------------------------------------------------
|
|
=head3 refreshNotification
|
|
It loads the notification info from the "notification"
|
|
table and store it into %notif variable.
|
|
The format of it is:
|
|
{tablename=>{filename=>{'ops'=>['y/n','y/n','y/n'], 'disable'=>'y/n'}}}
|
|
Arguments:
|
|
none
|
|
Returns:
|
|
none
|
|
=cut
|
|
#-------------------------------------------------------------------------------
|
|
sub refreshNotification
|
|
{
|
|
#print "refreshNotification get called\n";
|
|
#flush the cache
|
|
%notif=();
|
|
my $table=xCAT::Table->new("notification", -create =>0);
|
|
if ($table) {
|
|
#get array of rows out of the notification table
|
|
my @row_array= $table->getTable;
|
|
if (@row_array) {
|
|
#store the information to the cache
|
|
foreach(@row_array) {
|
|
my $module=$_->{filename};
|
|
my $ops=$_->{tableops};
|
|
my $disable= $_->{disable};
|
|
my @tablenames=split(/,/, $_->{tables});
|
|
|
|
foreach(@tablenames) {
|
|
if (!exists($notif{$_})) {
|
|
$notif{$_}={};
|
|
}
|
|
|
|
|
|
my $tempdisable=0;
|
|
if ($disable) {
|
|
if ($disable =~ m/^(yes|YES|Yes|Y|y|1)$/) {
|
|
$tempdisable=1;
|
|
}
|
|
}
|
|
|
|
if (!$disable) {
|
|
if ($ops) {
|
|
if ($ops =~ m/a/) {
|
|
if (exists($notif{$_}->{a})) {
|
|
my $pa=$notif{$_}->{a};
|
|
push(@$pa, $module);
|
|
} else {
|
|
$notif{$_}->{a}=[$module];
|
|
}
|
|
}
|
|
if ($ops =~ m/d/) {
|
|
if (exists($notif{$_}->{d})) {
|
|
my $pa=$notif{$_}->{d};
|
|
push(@$pa, $module);
|
|
} else {
|
|
$notif{$_}->{d}=[$module];
|
|
}
|
|
}
|
|
if ($ops =~ m/u/) {
|
|
if (exists($notif{$_}->{u})) {
|
|
my $pa=$notif{$_}->{u};
|
|
push(@$pa, $module);
|
|
} else {
|
|
$notif{$_}->{u}=[$module];
|
|
}
|
|
}
|
|
} #end if
|
|
}
|
|
} #end foreach
|
|
|
|
} #end foreach(@row_array)
|
|
}#end if (@row_array)
|
|
} #end if ($table)
|
|
|
|
#print Dumper(%notif);
|
|
return 1;
|
|
}
|
|
|
|
|
|
#--------------------------------------------------------------------------------
|
|
=head3 dumpNotificationCache
|
|
It print out the content of the notification cache for debugging purpose.
|
|
Arguments:
|
|
none
|
|
Returns:
|
|
0
|
|
=cut
|
|
#-------------------------------------------------------------------------------
|
|
sub dumpNotificationCache {
|
|
print "dump the notification cache:\n";
|
|
foreach(keys(%notif)) {
|
|
my $tmptn=$_;
|
|
print " $tmptn: \n";
|
|
|
|
if (exists($notif{$_}->{a})) {
|
|
print " a--:";
|
|
my $files=$notif{$_}->{a};
|
|
print "@$files\n";
|
|
}
|
|
if (exists($notif{$_}->{u})) {
|
|
print " u--:";
|
|
my $files=$notif{$_}->{u};
|
|
print "@$files\n";
|
|
}
|
|
if (exists($notif{$_}->{d})) {
|
|
print " d--:";
|
|
my $files=$notif{$_}->{d};
|
|
print "@$files\n";
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
#--------------------------------------------------------------------------------
|
|
=head3 needToNotify
|
|
It check if the given table has interested parties watching for its changes.
|
|
Arguments:
|
|
tablename - the name of the table to be checked.
|
|
tableop - the operation on the table. 'a' for add, 'u' for update
|
|
and 'd' for delete.
|
|
Returns:
|
|
1 - if the table has interested parties.
|
|
0 - if no parties are interested in its changes.
|
|
=cut
|
|
#-------------------------------------------------------------------------------
|
|
sub needToNotify {
|
|
|
|
#print "needToNotify pid=$$, notify=" . Dumper(%notif) . "\n";
|
|
|
|
if (!%notif) {
|
|
# print "notif not defined\n";
|
|
refreshNotification();
|
|
}
|
|
|
|
my $tablename=shift;
|
|
if ($tablename =~ /xCAT::NotifHandler/) {
|
|
$tablename=shift;
|
|
}
|
|
my $tableop=shift;
|
|
|
|
if (%notif) {
|
|
if (exists($notif{$tablename})) {
|
|
if (exists($notif{$tablename}->{$tableop})) {
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
#--------------------------------------------------------------------------------
|
|
=head3 notify
|
|
It notifies the registered the modules with the latest changes in
|
|
a DB table.
|
|
Arguments:
|
|
action - table action. It can be d for rows deleted, a for rows added
|
|
or u for rows updated.
|
|
tablename - string. The name of the DB table whose data has been changed.
|
|
old_data - an array reference of the old row data that has been changed.
|
|
The first element is an array reference that contains the column names.
|
|
The rest of the elelments are also array references each contains
|
|
attribute values of a row.
|
|
It is set when the action is u or d.
|
|
new_data - a hash refernce of new row data; only changed values are present
|
|
in the hash. It is keyed by column names.
|
|
It is set when the action is u or a.
|
|
Returns:
|
|
0
|
|
Comments:
|
|
If the curent table is watched by a perl module, the module must implement
|
|
the following routine:
|
|
processTableChanges(action, table_name, old_data, new_data)
|
|
If it is a watched by a command, the data will be passed to the command
|
|
through STDIN. The format is:
|
|
action
|
|
table_name
|
|
[old data]
|
|
col1_name,col2_name,...
|
|
col1_value,col2_value,...
|
|
...
|
|
[new data]
|
|
col1_name,col2_name,...
|
|
col1_value,col2_value,...
|
|
...
|
|
|
|
=cut
|
|
#-------------------------------------------------------------------------------
|
|
sub notify {
|
|
my $action=shift;
|
|
if ($action =~ /xCAT::NotifHandler/) {
|
|
$action=shift;
|
|
}
|
|
my $tablename=shift;
|
|
my $old_data=shift;
|
|
my $new_data=shift;
|
|
|
|
# print "notify called: tablename=$tablename, action=$action\n";
|
|
|
|
my @filenames=();
|
|
if (%notif) {
|
|
if (exists($notif{$tablename})) {
|
|
if (exists($notif{$tablename}->{$action})) {
|
|
my $pa=$notif{$tablename}->{$action};
|
|
@filenames=@$pa;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
foreach(@filenames) {
|
|
my ($modname, $path, $suffix) = fileparse($_, ".pm");
|
|
# print "modname=$modname, path=$path, suffix=$suffix\n";
|
|
if ($suffix =~ /.pm/) { #it is a perl module
|
|
my $fname;
|
|
if (($path eq "") || ($path eq ".\/")) {
|
|
#default path is /opt/xcat/lib/perl/xCAT_monitoring/ if there is no path specified
|
|
$fname = "$::XCATROOT/lib/perl/xCAT_monitoring/".$modname.".pm";
|
|
} else {
|
|
$fname = $_;
|
|
}
|
|
eval {require($fname)};
|
|
if ($@) {
|
|
print "The file $fname cannot be located or has compiling errors.\n";
|
|
}
|
|
else {
|
|
${"xCAT_monitoring::".$modname."::"}{processTableChanges}->($action, $tablename, $old_data, $new_data);
|
|
}
|
|
return 0;
|
|
}
|
|
else { #it is a command
|
|
my $pid;
|
|
if ($pid=xCAT::Utils->xfork()) { }
|
|
elsif (defined($pid)) {
|
|
# print "command=$_\n";
|
|
if (open(CMD, "|$_")) {
|
|
print(CMD "$action\n");
|
|
print(CMD "$tablename\n");
|
|
|
|
print(CMD "[old data]\n");
|
|
foreach (@$old_data) {
|
|
print(CMD join(',', @$_)."\n");
|
|
}
|
|
|
|
print(CMD "[new data]\n");
|
|
if (%$new_data) {
|
|
print(CMD join(',', keys %$new_data) . "\n");
|
|
print(CMD join(',', values %$new_data) . "\n");
|
|
}
|
|
close(CMD) or print "Cannot close the command $_\n";
|
|
}
|
|
else {
|
|
print "Command $_ cannot be found\n";
|
|
}
|
|
|
|
exit 0;
|
|
} #elsif
|
|
}
|
|
} #foreach
|
|
|
|
return 0;
|
|
}
|
|
|