Commit 3285bc3e authored by Leigh Stoller's avatar Leigh Stoller

Lots of little changes for sending email to the right places, with

proper headers. Split out some of the mail into testbed-logs,
testbed-ops, and testbed-approval. Added a library for including from
our perl scripts. Contains a couple of mail helper functions, but will
hopefully contain more as time goes by.

Fixed a bug in the web interface that was causing breakage for people
with multiple accounts. Mac and Jay have noticed this, when logging
out and trying to join or create a project under a new or different
name.
parent ab0486e5
......@@ -24,7 +24,7 @@ LIBEXEC_STUFF = mkprojdir rmproj mkacct-ctrl rmacct-ctrl \
os_setup mkexpdir console_setup webnscheck \
webstartexp webendexp webbatchexp webkillbatchexp
LIB_STUFF = libtbsetup.pm
LIB_STUFF = libtbsetup.pm libtestbed.pm
#
# Force dependencies on the scripts so that they will be rerun through
......
......@@ -23,6 +23,7 @@ my $optlist = "d";
my $TB = "@prefix@";
my $DBNAME = "@TBDBNAME@";
my $TBOPS = "@TBOPSEMAIL@";
my $TBLOGS = "@TBLOGSEMAIL@";
my $tbbindir = "$TB/bin/";
my $batchdir = "$TB/batch";
......@@ -42,7 +43,7 @@ my $eid;
my $pid;
my $logname;
my $nsfile;
my $user_name = "Batch Daemon";
my $user_name = "Testbed Operations";
my $user_email = "$TBOPS";
#
......@@ -50,6 +51,12 @@ my $user_email = "$TBOPS";
#
$| = 1;
#
# Testbed Support library
#
push(@INC, "$TB/lib");
require libtestbed;
#
# Untaint the path
#
......@@ -544,50 +551,47 @@ sub email_status($)
sub notify_user($$$)
{
my($mesg, $subline, $iserr) = @_;
my($to,$cc);
my($mesg, $subtext, $iserr) = @_;
my $subject, $from, $to, $cc;
my $MAIL;
print STDOUT "$mesg\n";
#
# If an error, goes to TBOPS and is CC'ed to user.
# Otherwise goes to user and is CC'ed to TBOPS
#
$subject = "TESTBED: Batch Mode Experiment $subtext $pid/$eid";
$from = $TBOPS;
$to = "$user_name <$user_email>";
if ($iserr) {
$to = $TBOPS;
$cc = $user_email;
$cc = "Cc: $TBOPS";
}
else {
$to = $user_email;
$cc = $TBOPS;
$cc = "Bcc: $TBLOGS";
}
open(MAIL, "| /usr/bin/mail ".
"-s \"TESTBED: Batch Mode Experiment $subline $pid/$eid\" ".
"-c $cc $to >/dev/null 2>&1")
or die "Cannot start mail program: $!";
if (! ($MAIL = OPENMAIL($to, $subject, $from, $cc))) {
die("Cannot start mail program!");
}
print MAIL $mesg;
print $MAIL $mesg;
if (defined($logname) && open(IN, "$logname")) {
print MAIL "\n\n---------\n\n";
print $MAIL "\n\n---------\n\n";
while (<IN>) {
print MAIL "$_";
print $MAIL "$_";
}
close(IN);
}
if (defined($nsfile) && open(IN, "$nsfile")) {
print MAIL "\n\n---------\n\n";
print $MAIL "\n\n---------\n\n";
while (<IN>) {
print MAIL "$_";
print $MAIL "$_";
}
close(IN);
}
close(MAIL);
close($MAIL);
}
#
......
......@@ -19,7 +19,6 @@ my $optlist = "";
#
my $TB = "@prefix@";
my $DBNAME = "@TBDBNAME@";
my $TBOPS = "@TBOPSEMAIL@";
my $tbbindir = "$TB/bin/";
my $batchdir = "$TB/batch";
......
......@@ -27,6 +27,7 @@ my $optlist = "b";
my $TB = "@prefix@";
my $DBNAME = "@TBDBNAME@";
my $TBOPS = "@TBOPSEMAIL@";
my $TBLOGS = "@TBLOGSEMAIL@";
my $tbdir = "$TB/bin/";
my $projroot = "/proj";
......@@ -45,6 +46,12 @@ delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
#
$| = 1;
#
# Testbed Support library
#
push(@INC, "$TB/lib");
require libtestbed;
#
# Parse command arguments. Once we return from getopts, all that should
# left are the required arguments.
......@@ -229,26 +236,27 @@ if ($batch) {
#
# Send email notification if not in batch mode.
#
open(MAIL, "| /usr/bin/mail ".
"-s \"TESTBED: Experiment $pid/$eid Terminated\" ".
"-c $TBOPS \"$user_name <$user_email>\" >/dev/null 2>&1")
or die "Cannot start mail program: $!";
print MAIL "Experiment `$eid' in project `$pid' has been terminated.\n";
print MAIL "You may now reuse `$eid' as an experiment name.\n\n";
print MAIL "Appended below is the output of the experiment teardown.\n";
print MAIL "If you have any questions or comments, please include the\n";
print MAIL "output below in your message to $TBOPS\n";
print MAIL "\n\n---------\n\n";
#
if (! ($MAIL = OPENMAIL("$user_name <$user_email>",
"TESTBED: Experiment $pid/$eid Terminated",
undef, "Bcc: $TBLOGS"))) {
die("Cannot start mail program!");
}
print $MAIL "Experiment `$eid' in project `$pid' has been terminated.\n";
print $MAIL "You may now reuse `$eid' as an experiment name.\n\n";
print $MAIL "Appended below is the output of the experiment teardown.\n";
print $MAIL "If you have any questions or comments, please include the\n";
print $MAIL "output below in your message to $TBOPS\n";
print $MAIL "\n\n---------\n\n";
if (open(IN, "$logname")) {
while (<IN>) {
print MAIL "$_";
print $MAIL "$_";
}
close(IN);
}
close(MAIL);
close($MAIL);
unlink("$logname");
exit 0;
......@@ -256,7 +264,8 @@ exit 0;
sub fatal()
{
my($mesg) = $_[0];
local $MAIL;
print STDOUT $mesg;
#
......@@ -270,22 +279,23 @@ sub fatal()
# Send a message to the testbed list. Append the logfile if it got
# that far.
#
open(MAIL, "| /usr/bin/mail ".
"-s \"TESTBED: Termination Failure $pid/$eid\" ".
"$TBOPS >/dev/null 2>&1")
or die "Cannot start mail program: $!";
if (! ($MAIL = OPENMAIL("$user_name <$user_email>",
"TESTBED: Termination Failure: $pid/$eid",
undef, "Cc: $TBOPS"))) {
die("Cannot start mail program!");
}
print MAIL $mesg;
print $MAIL $mesg;
if (open(IN, "$logname")) {
print MAIL "\n\n---------\n\n";
print $MAIL "\n\n---------\n\n";
while (<IN>) {
print MAIL "$_";
print $MAIL "$_";
}
close(IN);
}
close(MAIL);
close($MAIL);
unlink("$logname");
exit(-1);
......
......@@ -44,6 +44,12 @@ delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
$| = 1; #Turn off line buffering on output
#
# Testbed Support library
#
push(@INC, "$TB/lib");
require libtestbed;
#
# Set up for querying the database.
#
......@@ -198,8 +204,7 @@ exit(0);
sub fatal {
local($msg) = $_[0];
system("echo \"$msg\" | /usr/bin/mail ".
"-s 'TESTBED: Named Setup Failed' $TBOPS");
SENDMAIL($TBOPS, "TESTBED: Exports Setup Failed", $msg);
die($msg);
}
......
......@@ -30,6 +30,12 @@ my $projroot = "/proj";
#
$| = 1;
#
# Testbed Support library
#
push(@INC, "$TB/lib");
require libtestbed;
#
# Untaint the path
#
......@@ -144,13 +150,8 @@ sub fatal($)
#
# Send a message to the testbed list
#
open(MAIL, "| /usr/bin/mail ".
"-s \"TESTBED: Batch Mode Cancelation Failure $pid/$eid\" ".
"$TBOPS >/dev/null 2>&1")
or die "Cannot start mail program: $!";
print MAIL $mesg;
close(MAIL);
SENDMAIL($TBOPS,
"TESTBED: Batch Mode Cancelation Failure $pid/$eid", $mesg);
exit(-1);
}
......
#!/usr/bin/perl -w
use English;
#
# A library of useful stuff.
#
#
# Send an email message via sendmail -t.
#
# I am mimicking the PHP mail interface, only because I'm old and its
# hard to remember new things. I did add a From arg since thats basically
# required to make the mail look nice (not generated by root or daemon!).
#
# SENDMAIL(To, Subject, Message, [From], [More Headers])
#
sub SENDMAIL($$$;$$)
{
my($To, $Subject, $Message, $From, $Headers) = @_;
if (! open(MAIL, "|/usr/sbin/sendmail -t")) {
print STDERR "SENDMAIL: Could not start sendmail: $!\n";
return 0;
}
#
# Sendmail will figure this out if not given.
#
if (defined($From) && $From) {
print MAIL "From: $From\n";
}
print MAIL "To: $To\n";
print MAIL "Subject: $Subject\n";
if (defined($Headers)) {
print MAIL "$Headers\n";
}
print MAIL "\n";
print MAIL "$Message\n";
print MAIL "\n";
if (! close(MAIL)) {
print STDERR "SENDMAIL: Could not finish sendmail: $!\n";
return 0;
}
return 1;
}
#
# Fire up a sendmail process, and return the handle for the caller
# to print the body of the message into. This is easer in many places.
#
# OPENMAIL(To, Subject, [From], [More Headers])
#
sub OPENMAIL($$;$$)
{
my($To, $Subject, $From, $Headers) = @_;
local *MAIL;
if (! open(MAIL, "|/usr/sbin/sendmail -t")) {
print STDERR "OPENMAIL: Could not start sendmail: $!\n";
return 0;
}
#
# Sendmail will figure this out if not given.
#
if (defined($From) && $From) {
print MAIL "From: $From\n";
}
print MAIL "To: $To\n";
print MAIL "Subject: $Subject\n";
if (defined($Headers)) {
print MAIL "$Headers\n";
}
print MAIL "\n";
return(*MAIL);
}
1;
......@@ -13,6 +13,7 @@ use Fcntl ':flock';
#
my $TB = "@prefix@";
my $DBNAME = "@TBDBNAME@";
my $TBOPS = "@TBOPSEMAIL@";
my $mapdir = "/etc/namedb";
my $mapfile = "$mapdir/emulab.db";
......@@ -40,6 +41,12 @@ delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
$| = 1; #Turn off line buffering on output
#
# Testbed Support library
#
push(@INC, "$TB/lib");
require libtestbed;
#
# Set up for querying the database.
#
......@@ -158,7 +165,6 @@ exit(0);
sub fatal {
local($msg) = $_[0];
system("echo \"$msg\" | /usr/bin/mail ".
"-s 'TESTBED: Named Setup Failed' testbed-ops\@fast.cs.utah.edu");
SENDMAIL($TBOPS, "TESTBED: Named Setup Failed", $msg);
die($msg);
}
......@@ -199,7 +199,7 @@ sub RebootNode {
$syspid = fork();
if ($syspid) {
local $SIG{ALRM} = sub { kill("TERM", $syspid); };
alarm 30;
alarm 20;
waitpid($syspid, 0);
alarm 0;
......
......@@ -29,7 +29,6 @@ my $TBOPS = "@TBOPSEMAIL@";
my $nodereboot = "$TB/bin/node_reboot";
my $ping = "/sbin/ping";
my $mail = "/usr/bin/mail";
my $dbg = 0;
my @nodes = ();
my %osid = ();
......@@ -51,6 +50,12 @@ delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
$| = 1; #Turn off line buffering on output
#
# Testbed Support library
#
push(@INC, "$TB/lib");
require libtestbed;
#
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
......@@ -226,14 +231,13 @@ foreach my $node ( @nodes ) {
}
# Send mail to testbed-ops about it
open(MAIL,"| $mail -s \"TESTBED: $node down?\" $TBOPS");
print MAIL "User ".getpwuid($UID)." was running expt. $eid\n";
print MAIL "in proj. $pid using ir file /proj/$pid/exp/$eid/tbdata\n";
print MAIL "but $node appears to be unresponsive.\n";
print MAIL "\nPlease look into this matter. $node has been reserved to\n";
print MAIL "the testbed/down experiment until this has been resolved.\n\n";
print MAIL "Thanks,\nTestbed Operations\ntestbed-ops\@flux.cs.utah.edu\n";
close(MAIL);
SENDMAIL($TBOPS, "TESTBED: Node $node is down",
"User ".getpwuid($UID)." was running expt. $eid\n".
"in proj. $pid using ir file /proj/$pid/exp/$eid/tbdata\n".
"but $node appears to be unresponsive.\n\n".
"Please look into this matter. $node has been reserved to\n".
"the testbed/down experiment until this has been resolved.\n\n".
"Thanks,\n");
die("Oops, $node did not come back alive!\n");
}
......
......@@ -43,6 +43,12 @@ $| = 1;
$ENV{'PATH'} = "/bin:/usr/bin:";
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
#
# Testbed Support library
#
push(@INC, "$TB/lib");
require libtestbed;
#
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
......@@ -196,8 +202,7 @@ sub DBquery($)
sub fatal {
local($msg) = $_[0];
system("echo \"$msg\" | /usr/bin/mail ".
"-s 'TESTBED: Reload Daemon Died' $TBOPS");
SENDMAIL($TBOPS, "TESTBED: Reload Daemon Died", $msg);
die($msg);
}
......
......@@ -30,6 +30,7 @@ my $optlist = "b:";
my $TB = "@prefix@";
my $DBNAME = "@TBDBNAME@";
my $TBOPS = "@TBOPSEMAIL@";
my $TBLOGS = "@TBLOGSEMAIL@";
my $TBINFO = "$TB/expinfo";
my $tbdir = "$TB/bin/";
......@@ -57,6 +58,12 @@ $| = 1;
$ENV{'PATH'} = '/bin:/usr/bin';
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
#
# Testbed Support library
#
push(@INC, "$TB/lib");
require libtestbed;
#
# Parse command arguments. Once we return from getopts, all that should
# left are the required arguments.
......@@ -136,9 +143,9 @@ if ($query_result->numrows < 1) {
}
@row = $query_result->fetchrow_array();
if ($row[0]) {
fatal("Experiment $pid/$eid is already configured!\n".
"You are not allowed to reconfigure experiments unless you\n".
"first terminate the existing experiment via the web interface.\n");
die("Experiment $pid/$eid is already configured!\n".
"You are not allowed to reconfigure experiments unless you\n".
"first terminate the existing experiment via the web interface.\n");
}
#
......@@ -308,56 +315,58 @@ if ($batch) {
#
# Dump the report file and the log file to the user via email.
#
open(MAIL, "| /usr/bin/mail ".
"-s \"TESTBED: New Experiment Created: $pid/$eid\" ".
"-c $TBOPS \"$user_name <$user_email>\" >/dev/null 2>&1")
or die "Cannot start mail program: $!";
print MAIL "Your experiment `$eid' in project `$pid' is now configured.\n";
print MAIL "Here is the experiment summary detailing the nodes that were\n";
print MAIL "allocated to you. You may use the `Qualified Name' to log on\n";
print MAIL "to your nodes. See /etc/hosts on your nodes (when running\n";
print MAIL "FreeBSD, Linux, or NetBSD) for the IP name mapping on each node\n";
print MAIL "\n";
print MAIL "User: $user_name\n";
print MAIL "EID: $eid\n";
print MAIL "PID: $pid\n";
print MAIL "Name: $expt_name\n";
print MAIL "Created: $expt_created\n";
print MAIL "Expires: $expt_expires\n";
print MAIL "Directory: $eiddir\n\n";
if (! ($MAIL = OPENMAIL("$user_name <$user_email>",
"TESTBED: New Experiment Created: $pid/$eid",
undef, "Bcc: $TBLOGS"))) {
tbendit();
die("Cannot start mail program!");
}
print $MAIL "Your experiment `$eid' in project `$pid' is now configured.\n";
print $MAIL "Here is the experiment summary detailing the nodes that were\n";
print $MAIL "allocated to you. You may use the `Qualified Name' to log on\n";
print $MAIL "to your nodes. See /etc/hosts on your nodes (when running\n";
print $MAIL "FreeBSD, Linux, or NetBSD) for the IP mapping on each node\n";
print $MAIL "\n";
print $MAIL "User: $user_name\n";
print $MAIL "EID: $eid\n";
print $MAIL "PID: $pid\n";
print $MAIL "Name: $expt_name\n";
print $MAIL "Created: $expt_created\n";
print $MAIL "Expires: $expt_expires\n";
print $MAIL "Directory: $eiddir\n\n";
if (open(IN, "$repfile")) {
while (<IN>) {
print MAIL "$_";
print $MAIL "$_";
}
close(IN);
}
print MAIL "\n\n---------\n\n";
print $MAIL "\n\n---------\n\n";
print MAIL "Here is the log of the configuration process.\n";
print MAIL "If you have any questions or problems, please include the\n";
print MAIL "output below in your message to $TBOPS\n\n";
print $MAIL "Here is the log of the configuration process.\n";
print $MAIL "If you have any questions or problems, please include the\n";
print $MAIL "output below in your message to $TBOPS\n\n";
if (open(IN, "$logname")) {
while (<IN>) {
print MAIL "$_";
print $MAIL "$_";
}
close(IN);
}
if (open(IN, "$nsfile")) {
print MAIL "\n\n---------\n\n";
print MAIL "Here is the NS file\n\n";
print $MAIL "\n\n---------\n\n";
print $MAIL "Here is the NS file\n\n";
while (<IN>) {
print MAIL "$_";
print $MAIL "$_";
}
close(IN);
}
close(MAIL);
close($MAIL);
unlink("$tempns");
unlink("$logname");
......@@ -366,6 +375,7 @@ exit 0;
sub fatal()
{
my($mesg) = $_[0];
local $MAIL;
print STDOUT "$mesg\n";
print STDOUT "Cleaning up and exiting with status $errorstat ...\n";
......@@ -412,42 +422,43 @@ sub fatal()
#
# Send a message to the testbed list. Append the logfile if it got
# that far.
#
open(MAIL, "| /usr/bin/mail ".
"-s \"TESTBED: Experiment Configure Failure $pid/$eid\" ".
"-c $TBOPS \"$user_name <$user_email>\" >/dev/null 2>&1")
or die "Cannot start mail program: $!";
print MAIL $mesg;
#
if (! ($MAIL = OPENMAIL("$user_name <$user_email>",
"TESTBED: Experiment Configure Failure: $pid/$eid",
undef, "Cc: $TBOPS"))) {
die("Cannot start mail program!");
}
print $MAIL $mesg;
if (open(IN, "$tempns")) {
print MAIL "\n\n--------- $tempns ---------\n\n";
print $MAIL "\n\n--------- $tempns ---------\n\n";
while (<IN>) {
print MAIL "$_";
print $MAIL "$_";
}
close(IN);
unlink("$tempns");
}
if (open(IN, "$logname")) {
print MAIL "\n\n--------- $logname ---------\n\n";
print $MAIL "\n\n--------- $logname ---------\n\n";
while (<IN>) {
print MAIL "$_";
print $MAIL "$_";
}
close(IN);
}
if (open(IN, "$eiddir/assign.log")) {
print MAIL "\n\n--------- assign.log --------\n\n";
print $MAIL "\n\n--------- assign.log --------\n\n";
while (<IN>) {
print MAIL "$_";
print $MAIL "$_";
}
close(IN);
}
close(MAIL);
close($MAIL);
unlink("$tempns");
unlink("$logname");
......
......@@ -55,7 +55,8 @@ if ($returning) {
echo "<tr>
<td>*Username (no blanks, lowercase):</td>
<td class=\"left\">
<input type=\"readonly\" name=\"uid\" value=\"$uid\"></td>
<input type=\"readonly\" name=\"joining_uid\"
value=\"$uid\"></td>
</tr>\n";
echo "<tr>
......@@ -118,7 +119,7 @@ else {
echo "<tr>
<td>*Username:</td>
<td class=\"left\">
<input type=\"text\" name=\"uid\"
<input type=\"text\" name=\"joining_uid\"
size=$TBDB_UIDLEN maxlength=$TBDB_UIDLEN></td>
</tr>\n";
......
......@@ -96,8 +96,8 @@ elseif (strcmp($approval, "moreinfo") == 0) {
"Thanks,\n".
"Testbed Ops\n".
"Utah Network Testbed\n",
"From: $TBMAIL_CONTROL\n".
"Cc: $TBMAIL_CONTROL\n".
"From: $TBMAIL_APPROVAL\n".
"Bcc: $TBMAIL_APPROVAL\n".
"Errors-To: $TBMAIL_WWW");
echo "<p><h3>
......@@ -136,8 +136,8 @@ elseif ((strcmp($approval, "deny") == 0) ||
"Thanks,\n".
"Testbed Ops\n".
"Utah Network Testbed\n",
"From: $TBMAIL_CONTROL\n".
"Cc: $TBMAIL_CONTROL\n".
"From: $TBMAIL_APPROVAL\n".
"Bcc: $TBMAIL_APPROVAL\n".
"Errors-To: $TBMAIL_WWW");
#
......@@ -162,8 +162,8 @@ elseif ((strcmp($approval, "deny") == 0) ||
"Thanks,\n".
"Testbed Ops\n".
"Utah Network Testbed\n",
"From: $TBMAIL_CONTROL\n".
"Cc: $TBMAIL_CONTROL\n".
"From: $TBMAIL_APPROVAL\n".
"Bcc: $TBMAIL_APPROVAL\n".
"Errors-To: $TBMAIL_WWW");
}
......@@ -213,30 +213,6 @@ elseif (strcmp($approval, "approve") == 0) {
"$newstatus.",
1);
}
#
# For new leaders, write their email addresses to files to be used for
# generating messages.
#
$fp = fopen($TBLIST_LEADERS, "a");
if (! $fp) {
TBERROR("Could not open $TBLIST_LEADERS to add new ".
"project leader email: $headuid_email\n", 0);
}
else {
fwrite($fp, "$headuid_email\n");
fclose($fp);
}
$fp = fopen($TBLIST_USERS, "a");
if (! $fp) {
TBERROR("Could not open $TBLIST_USERS to add new ".
"project leader email: $headuid_email\n", 0);
}
else {
fwrite($fp, "$headuid_email\n");
fclose($fp);
}
}
mail("$headname '$headuid' <$headuid_email>",
......@@ -249,8 +225,8 @@ elseif (strcmp($approval, "approve") == 0) {
"Thanks,\n".
"Testbed Ops\n".
"Utah Network Testbed\n",
"From: $TBMAIL_CONTROL\n".
"Cc: $TBMAIL_CONTROL\n".
"From: $TBMAIL_APPROVAL\n".
"Bcc: $TBMAIL_APPROVAL\n".
"Errors-To: $TBMAIL_WWW");
#
......
......@@ -117,6 +117,22 @@ while (list ($header, $value) = each ($HTTP_POST_VARS)) {
USERERROR("User $user is already a member of project $project.", 1);
}
#
# Lets get the uid email for the mail messages below, so that we
# can stick in a proper return address.