Commit 07dda0d8 authored by Kevin Atkinson's avatar Kevin Atkinson

Prep for Mike Kasick report code.  Updated database schema and
installed hooks for his code.

Cleaned up how errors were handled in tblog(...).

Allow SENDMAIL to be called before the path is untained in '-T' scripts.

Other small changes.
parent 09d78ac6
......@@ -4664,11 +4664,11 @@ sub DBWarn($;$)
#
# usage: DBFatal(char *message);
#
sub DBFatal($)
sub DBFatal($;$)
{
my($message) = $_[0];
my($message,$nomail) = $_[0];
DBError(\&tbdie, $message);
DBError(\&tbdie, $message, $nomail);
}
#
......
......@@ -1267,7 +1267,7 @@ CREATE TABLE location_info (
--
CREATE TABLE log (
seq int(10) unsigned NOT NULL auto_increment,
seq int(10) unsigned NOT NULL default '0',
stamp int(10) unsigned NOT NULL default '0',
session int(10) unsigned NOT NULL default '0',
attempt tinyint(1) NOT NULL default '0',
......@@ -1280,7 +1280,7 @@ CREATE TABLE log (
priority smallint(3) NOT NULL default '0',
inferred tinyint(1) NOT NULL default '0',
cause varchar(16) NOT NULL default '',
type enum('normal','entering','exiting','thecause','extra','summary') NOT NULL default 'normal',
type enum('normal','entering','exiting','thecause','extra','summary','primary','secondary') default 'normal',
relevant tinyint(1) NOT NULL default '0',
mesg text NOT NULL,
PRIMARY KEY (seq),
......@@ -2120,6 +2120,58 @@ CREATE TABLE projects (
KEY pcremote_ok (pcremote_ok)
) TYPE=MyISAM;
--
-- Table structure for table `report_assign_violation`
--
CREATE TABLE `report_assign_violation` (
`seq` int(10) unsigned NOT NULL,
`unassigned` int(11) default NULL,
`pnode_load` int(11) default NULL,
`no_connect` int(11) default NULL,
`link_users` int(11) default NULL,
`bandwidth` int(11) default NULL,
`desires` int(11) default NULL,
`vclass` int(11) default NULL,
`delay` int(11) default NULL,
`trivial_mix` int(11) default NULL,
`subnodes` int(11) default NULL,
`max_types` int(11) default NULL,
`endpoints` int(11) default NULL,
PRIMARY KEY (`seq`)
) TYPE=MyISAM;
--
-- Table structure for table `report_context`
--
CREATE TABLE `report_context` (
`seq` int(10) unsigned NOT NULL,
`i0` int(11) default NULL,
`i1` int(11) default NULL,
`i2` int(11) default NULL,
`vc0` varchar(255) default NULL,
`vc1` varchar(255) default NULL,
`vc2` varchar(255) default NULL,
PRIMARY KEY (`seq`)
) TYPE=MyISAM;
--
-- Table structure for table `report_error`
--
CREATE TABLE `report_error` (
`seq` int(10) unsigned NOT NULL,
`stamp` int(10) unsigned NOT NULL,
`session` int(10) unsigned NOT NULL,
`attempt` tinyint(1) NOT NULL,
`severity` smallint(3) NOT NULL,
`script` smallint(3) NOT NULL,
`error_type` varchar(255) NOT NULL,
PRIMARY KEY (`seq`),
KEY `session` (`session`)
) TYPE=MyISAM;
--
-- Table structure for table `reposition_status`
--
......
......@@ -20,3 +20,5 @@ INSERT IGNORE INTO os_boot_cmd VALUES ('FreeBSD','5.4','linkdelay','/boot/kernel
INSERT IGNORE INTO os_boot_cmd VALUES ('Linux','9.0','linkdelay','linkdelay');
INSERT IGNORE INTO os_boot_cmd VALUES ('FreeBSD','6.0','delay','/boot/kernel.delay/kernel');
INSERT IGNORE INTO os_boot_cmd VALUES ('FreeBSD','6.0','linkdelay','/boot/kernel.linkdelay/kernel');
INSERT IGNORE INTO emulab_indicies (name,idx) VALUES ('cur_log_seq', 1);
......@@ -3334,6 +3334,8 @@ last_net_act,last_cpu_act,last_ext_act);
drop column uid,
drop column exptidx;
lock tables log read, session_info read;
[Now install the new code, do it before you unlock the table, as
the last statement made an incompatible change to the "log" table]
......@@ -3620,3 +3622,30 @@ last_net_act,last_cpu_act,last_ext_act);
PRIMARY KEY (parent_guid, parent_vers, vname)
) TYPE=MyISAM;
4.82: Add Support For Mike Kasick Reporter Mechanism. This need to be
done in two parts.
1) Add report_* tables:
mysql tbdb < tbreport.sql
2) Modify exiting tables:
lock tables log write, emulab_indicies write;
insert into emulab_indicies (name,idx)
select 'cur_log_seq', max(seq) from log;
alter table log
change seq seq int unsigned not null default '0',
change type type enum('normal','entering','exiting','thecause',
'extra','summary','primary','secondary')
default 'normal';
lock tables log read, emulab_indicies read;
[Now install the new code, do it before you unlock the table,
otherwise risk cur_log_seq getting out if sync.]
unlock tables;
......@@ -205,7 +205,7 @@ use Exporter;
@ISA = "Exporter";
@EXPORT = qw (tblog tberror tberr tbwarn tbwarning tbnotice tbinfo tbdebug
tbdie tblog_set_info tblog_set_default_cause
tbdie tbreport tblog_set_info tblog_set_default_cause
tblog_sub_process tblog_find_error tblog_email_error
tblog_start_capture tblog_stop_capture
tblog_new_process tblog_init_process tblog_exit
......@@ -301,6 +301,15 @@ sub indent ( $$ ) {
return $res;
}
sub add_prefix ( $$ ) {
my ($prefix, $mesg) = @_;
if ($mesg =~ /\n./) {
return "$prefix:\n$mesg";
} else {
return "$prefix: $mesg";
}
}
#
#
#
......@@ -326,6 +335,27 @@ sub DBQuerySingleFatal ( $ )
return $row[0];
}
#
# Convert the script name to a number
#
sub script_name_to_num( $ ) {
my ($scriptname) = @_;
my $scriptnum;
my $query_result = DBQueryFatal
sprintf("select script from scripts where script_name=%s",
DBQuoteSpecial $scriptname);
if ($query_result->num_rows > 0) {
$scriptnum = ($query_result->fetchrow_array())[0];
} else {
DBQueryFatal
sprintf("insert into scripts (script_name) values (%s)",
DBQuoteSpecial $scriptname);
$scriptnum = DBQuerySingleFatal 'select LAST_INSERT_ID()';
}
return $scriptnum;
}
#
# Forward Decals
#
......@@ -398,17 +428,7 @@ sub tblog_init_process(@) {
# Get script number
my $query_result = DBQueryFatal
sprintf("select script from scripts where script_name=%s",
DBQuoteSpecial $ENV{TBLOG_SCRIPTNAME});
if ($query_result->num_rows > 0) {
$ENV{TBLOG_SCRIPTNUM} = ($query_result->fetchrow_array())[0];
} else {
DBQueryFatal
sprintf("insert into scripts (script_name) values (%s)",
DBQuoteSpecial $ENV{TBLOG_SCRIPTNAME});
$ENV{TBLOG_SCRIPTNUM} = DBQuerySingleFatal 'select LAST_INSERT_ID()';
}
$ENV{TBLOG_SCRIPTNUM} = script_name_to_num($ENV{TBLOG_SCRIPTNAME});
# ...
......@@ -416,10 +436,10 @@ sub tblog_init_process(@) {
check_env();
$ENV{TBLOG_LEVEL}++;
$ENV{TBLOG_PARENT_INVOCATION} = $ENV{TBLOG_INVOCATION};
dblog($NOTICE, {type => 'entering'},
'Entering "', join(' ', informative_scriptname(), @argv), '"')
my $id = dblog
($NOTICE, {type => 'entering'},
'Entering "', join(' ', informative_scriptname(), @argv), '"')
or die;
my $id = DBQuerySingleFatal 'select LAST_INSERT_ID()';
$ENV{TBLOG_INVOCATION} = $id;
DBQueryFatal("update log set invocation=$id where seq=$id");
} else {
......@@ -431,10 +451,10 @@ sub tblog_init_process(@) {
$ENV{TBLOG_UID} = 0;
$ENV{TBLOG_ATTEMPT} = 0;
$ENV{TBLOG_CLEANUP} = 0;
dblog($NOTICE, {type => 'entering'},
'Entering "', join(' ', informative_scriptname(), @ARGV), '"')
my $id = dblog
($NOTICE, {type => 'entering'},
'Entering "', join(' ', informative_scriptname(), @ARGV), '"')
or die;
my $id = DBQuerySingleFatal 'select LAST_INSERT_ID()';
# set SESSION in database
$ENV{TBLOG_SESSION} = $id;
$ENV{TBLOG_INVOCATION} = $id;
......@@ -641,11 +661,37 @@ not exactly like die as the message must be specified.
# NOTE: tblog (and friends) defined in libtblog_simple
#
#
# new_seq_num
#
my $sent_cur_log_seq_error_mail = 0;
sub new_seq_num (;$) {
my ($failure_action) = @_;
$failure_action = sub {DBFatal("DB Query failed")} unless defined $failure_action;
my $result;
$result = DBQuery("UPDATE emulab_indicies SET idx=LAST_INSERT_ID(idx+1) WHERE name = 'cur_log_seq'");
if (!$result) {
&$failure_action;
return;
} elsif ($result->affectedrows <= 0) {
my $subject = "Row \"cur_log_seq\" does not exist in emulab_indicies.";
my $message = "$subject\n";
$message .= "Please see \"database-migrate.txt\".";
SENDMAIL(TB_OPSEMAIL, "DBError - $subject", $message)
unless $sent_cur_log_seq_error_mail;
$sent_cur_log_seq_error_mail = 1;
die "$subject\n";
return;
}
my $seq = $result->insertid();
return $seq;
}
#
# dblog(priority, {parm=>value,...}, mesg, ...)
# Internal function. Logs a message to the database. Doesn't print
# anything. Will not die, instead return 0 on error, with the error
# message in $@.
# message in $@. Otherwise will return the seq number.
# Valid parms: sublevel, cause, type
#
my $in_dblog = 0; # Used to avoid an infinite recursion when
......@@ -655,6 +701,7 @@ my $in_dblog = 0; # Used to avoid an infinite recursion when
sub dblog_real ( $$@ ) {
my ($priority, $parms, @mesg) = @_;
my $mesg = join('',@mesg);
my $seq;
#print SERR "===$priority $parms @mesg\n";
return if $ENV{TBLOG_OFF} || $in_dblog;
$in_dblog = 1;
......@@ -667,47 +714,93 @@ sub dblog_real ( $$@ ) {
$cause = $priority <= $WARNING ? $ENV{TBLOG_CAUSE} : ''
unless defined $cause;
my $query =
sprintf('insert into log (stamp,session,attempt,cleanup,parent,invocation,script,level,sublevel,priority,inferred,cause,type,mesg) '.
'VALUES (UNIX_TIMESTAMP(now()),%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%s,%s,%s)',
$ENV{TBLOG_SESSION},
$ENV{TBLOG_ATTEMPT},
$ENV{TBLOG_CLEANUP},
$ENV{TBLOG_PARENT_INVOCATION},
$ENV{TBLOG_INVOCATION},
$ENV{TBLOG_SCRIPTNUM},
$ENV{TBLOG_LEVEL},
if_defined($parms->{sublevel}, 0),
$priority,
if_defined($parms->{inferred}, 0),
DBQuoteSpecial $cause,
DBQuoteSpecial if_defined($parms->{type}, 'normal'),
DBQuoteSpecial $mesg);
my $failure_action;
local $DBQUERY_MAXTRIES;
if ($priority <= $NOTICE) {
local $DBQUERY_MAXTRIES = 3;
my $result = DBQuery($query);
DBWarn("Could not log entry to DB, tblog_find_error may report incorrect results") unless $result;
$DBQUERY_MAXTRIES = 3;
$failure_action = sub {
DBFatal("Could not log entry to DB, tblog_find_error may report incorrect results");
};
} else {
my $result = DBQuery($query);
DBWarn("Could not log entry to DB", 1) unless $result;
$DBQUERY_MAXTRIES = 1;
$failure_action = sub {
DBFatal("Could not log entry to DB", 1);
};
}
$seq = new_seq_num($failure_action);
my $result = DBQuery
(sprintf('insert into log (seq,stamp,session,attempt,cleanup,parent,invocation,script,level,sublevel,priority,inferred,cause,type,mesg) '.
'VALUES (%d,UNIX_TIMESTAMP(now()),%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%s,%s,%s)',
$seq,
$ENV{TBLOG_SESSION},
$ENV{TBLOG_ATTEMPT},
$ENV{TBLOG_CLEANUP},
$ENV{TBLOG_PARENT_INVOCATION},
$ENV{TBLOG_INVOCATION},
$ENV{TBLOG_SCRIPTNUM},
$ENV{TBLOG_LEVEL},
if_defined($parms->{sublevel}, 0),
$priority,
if_defined($parms->{inferred}, 0),
DBQuoteSpecial $cause,
DBQuoteSpecial if_defined($parms->{type}, 'normal'),
DBQuoteSpecial $mesg));
&$failure_action unless $result;
};
$in_dblog = 0;
# Print a warning on failure but don't log the results to the database
# as that is likely to fail also
print SERR format_message(scriptname(), $WARNING, $@) if $@;
print SERR format_message(scriptname(), $WARNING,
add_prefix("dblog failed", $@)) if $@;
return 0 if $@;
return 1;
if ($parms->{error}) {
tbreport($parms->{severity},
{seq => $seq, script => $parms->{real_script}},
@{$parms->{error}});
}
return $seq;
}
{
local $^W = 0;
*dblog = \&dblog_real;
}
#
# FILLMEIN
#
sub tbreport( $@ ) {
my ($severity) = shift;
my $parms = {};
$parms = shift if ref $_[0] eq 'HASH';
my ($error_type, @context) = @_;
my $seq = $parms->{seq};
=item tblog_find_error
eval {
local $DBQUERY_MAXTRIES = 3;
check_env();
my $script_num = $ENV{TBLOG_SCRIPTNUM};
$script_num = script_name_to_num($parms->{script})
if defined $parms->{script};
$seq = new_seq_num() unless defined $seq;
my $session = $ENV{TBLOG_SESSION};
# FILLMEIN: Put your code here
print STDERR "IN TBREPORT\n";
};
# Print a warning on failure but don't log the results to the database
# as that is likely to fail also
print SERR format_message(scriptname(), $WARNING,
add_prefix("tbreport failed", $@)) if $@;
return 0 if $@;
return $seq;
}
=item tblog_find_error
Attempts to find the relevant error.
Will act in a way that is safe to use in an END block, that is (1)
......@@ -984,7 +1077,6 @@ sub tblog_find_error () {
DBQueryFatal
sprintf("update log set relevant=1 where seq in (%s)",
join(',', map {$_->{seq}} @relevant)) if @relevant;
};
my $err;
......@@ -999,7 +1091,7 @@ sub tblog_find_error () {
"\n".
"$err\n")};
eval {tblog $WARNING, "tblog_find_error failed: $err" };
eval {tblog $WARNING, add_prefix("tblog_find_error failed", $err)};
}
$? = $saved_exitcode;
......
......@@ -86,6 +86,13 @@ while (my ($n,$v) = each %PRIORITY_MAP_TO_STR) {
$PRIORITY_MAP_TO_NUM{lc $v} = $n;
}
#
# tbreport related constants
#
# FILLMEIN: Be sure that any exported constants don't conflict with
# tblog ones
#
# Utility functions
#
......@@ -179,9 +186,21 @@ sub tbdie( @ ) {
$parms = shift if ref $_[0] eq 'HASH';
my $mesg = join('',@_);
dblog($ERR, $parms, $mesg);
tblog_stop_capture() if exists $INC{'libtblog.pm'};
die format_message(scriptname(), $ERR, $mesg);
if ($^S) {
# Handle case when we are in an eval block special:
# 1) downgrade error to warning as it may not be fatal
# 2) Call tblog (not just dblog) to print the error since
# the message may never actually appear.
# 3) Don't stop capturing as we are not trully dying
# 4) Don't format message as it may be modified latter
tblog($WARNING, $parms, $mesg);
$mesg .= "\n" unless $mesg =~ /\n$/;
die $mesg;
} else {
dblog($ERR, $parms, $mesg);
tblog_stop_capture() if exists $INC{'libtblog.pm'};
die format_message(scriptname(), $ERR, $mesg);
}
}
#
......
......@@ -74,6 +74,13 @@ sub SENDMAIL($$$;$$@)
my($To, $Subject, $Message, $From, $Headers, @Files) = @_;
my $tag = uc($MAILTAG);
#
# Untaint the path locally
#
local %ENV = %ENV;
$ENV{PATH} = "/bin:/usr/bin";
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
if (! open(MAIL, "|/usr/sbin/sendmail -t")) {
print STDERR "SENDMAIL: Could not start sendmail: $!\n";
return 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment