genelists.in 5.48 KB
Newer Older
1
#!/usr/bin/perl -wT
2
use Fcntl ':flock';
3
use English;
4
use Getopt::Std;
5 6

sub usage() {
7 8 9 10
    print STDOUT "Usage: genelists [-a] [-n uid]\n".
	"Generate the email list files after things change.\n".
	"Use the -a option to generate lists for all projects.\n".
	"Use the -n option to generate lists for a new user.\n";
11 12
    exit(-1);
}
13
my  $optlist = "an:";
14 15 16 17

# Configure variables
my $TB		= "@prefix@";
my $TBOPS       = "@TBOPSEMAIL@";
18
my $USERS       = "@USERNODE@";
19 20
my $TBACTIVE    = "@TBACTIVEARCHIVE@";
my $TBALL       = "@TBUSERSARCHIVE@";
21
my $PROJROOT	= "/proj";
22 23

# Note no -n option. We redirect stdin from the new exports file below.
24
my $SSH		= "$TB/bin/sshtb -l root $USERS";
25
my $PROG	= "/usr/testbed/sbin/genelists.proxy";
26
my $lockfile    = "/var/tmp/testbed_genelists_lockfile";
27
my $tempfile    = "/var/tmp/testbed_genelists_tempfile";
28 29
my $newuser;
my $allprojects;
30 31
my $d = 0;

32 33 34 35
#
# Turn off line buffering on output
#
$| = 1; 
36 37

# Load the Testbed support stuff.
38 39 40
use lib "@prefix@/lib";
use libdb;
use libtestbed;
41

42 43 44 45
#
# We don't want to run this script unless its the real version.
#
if ($EUID != 0) {
Leigh B. Stoller's avatar
Leigh B. Stoller committed
46 47
    die("*** $0:\n".
	"    Must be root! Maybe its a development version?\n");
48 49
}
# XXX Hacky!
50
if (1 && $TB ne "/usr/testbed") {
Leigh B. Stoller's avatar
Leigh B. Stoller committed
51 52
    die("*** $0:\n".
	"    Wrong version. Maybe its a development version?\n");
53
}
54 55 56 57 58 59 60

#
# un-taint path
#
$ENV{'PATH'} = '/bin:/usr/bin:/usr/sbin:/usr/local/bin';
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};

61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
#
# Parse command arguments. Once we return from getopts, all that should
# left are the required arguments.
#
%options = ();
if (! getopts($optlist, \%options)) {
    usage();
}
if (@ARGV) {
    usage();
}
if (defined($options{"a"})) {
    $allprojects = 1;
}
if (defined($options{"n"})) {
    $newuser = $options{"n"};
    #
    # Untaint.
    #
    if ($newuser =~ /^([-\w]+)$/) {
	$newuser = $1;
    }
    else {
	die("Tainted argument $newuser!\n");
    }
}
if (defined($newuser) && defined($allprojects)) {
88 89 90
    usage();
}

91 92 93 94 95 96 97 98 99 100 101 102 103
# Set up a mutex so this doesn't get run twice at the same time

open(LOCK, ">>$lockfile") || fatal("Couldn't open $lockfile\n");
$count = 0;
while (flock(LOCK, LOCK_EX|LOCK_NB) == 0) {
    print "Another genelists in progress. Waiting a moment ...\n";
    if ($count++ > 20) {
	fatal("Could not get the lock after a long time!\n");
    }
    sleep(1);
}

foreach my $active ( 0, 1 ) {
104
    my $progarg;
105
    my $userlist;
106 107 108 109 110 111
    
    if ($active) {
	print "Getting Active Users\n" if $d;
	# All active users on the testbed
	if (! ($query_result =
	       DBQuery("SELECT DISTINCT u.usr_email from experiments as e ".
Leigh B. Stoller's avatar
Leigh B. Stoller committed
112 113
		       "left join group_membership as p ".
		       "     on e.pid=p.pid and p.pid=p.gid ".
114 115 116 117 118
		       "left join users as u on u.uid=p.uid ".
		       "where u.status='active' order by u.usr_email"))) {
	    DBFatal("Getting Active Users!");
	}
	$userlist = "$TBOPS\n".
119 120
	            "$TBACTIVE";
	$progarg  = "emulab-active-users";
121
    }
122 123 124 125 126 127 128 129 130
    else {
	print "Getting All Users\n" if $d;
	# All approved users on the testbed
	if (! ($query_result =
	       DBQuery("SELECT DISTINCT usr_email FROM users ".
		       "where status='active' order by usr_email"))) {
	    DBFatal("Getting Users!");
	}
	$userlist = "$TBOPS\n".
131 132
	            "$TBALL";
	$progarg  = "emulab-users";
133
    }
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
    genelist($query_result, $userlist, $progarg);
}

#
# Regen project lists. Either all the lists, or just the projects
# that "newuser" is a member of.
# 
if (defined($newuser) || defined($allprojects)) {
    my $proj_result;

    if (defined($newuser)) {
	$proj_result =
	    DBQueryFatal("select pid from group_membership ".
			 "where uid='$newuser' and pid=gid");
    }
    else {
	$proj_result =
	    DBQueryFatal("select pid from projects");
    }

    while (($pid) = $proj_result->fetchrow_array) {
	print "Getting project members for $pid\n" if $d;

	my $query_result =
	    DBQueryFatal("SELECT distinct u.usr_email from ".
			 " group_membership as p ".
			 "left join users as u on u.uid=p.uid ".
			 "where p.pid='$pid' and p.pid=p.gid and ".
			 " p.trust!='none' ".
			 "order by u.usr_email");

	if ($query_result->numrows) {
	    my $archive = "$PROJROOT/$pid/$pid-users.mail";

	    #
	    # This would be nice, but will not work since the mailer daemon
	    # cannot access files in /proj/$pid. 
	    #
	    if (0 && ! -e $archive) {
		open(ARCHIVE, ">>$archive") or
		    fatal("Could not create $archive: $!");
		close(ARCHIVE);
		
		chmod(0666, "$archive") or
		    fatal("Could not chmod(666) $archive: $!");
	    }
	    genelist($query_result, undef, "$pid-users");
	}
    }
}

#
# Generate and fire over a list.
#
sub genelist($$$)
{
    my($query_result, $inituserlist, $progarg) = @_;
191

192 193 194 195 196 197
    open(LIST,"> $tempfile") ||
	fatal("Couldn't open $tempfile: $!\n");
  
    print LIST "#\n";
    print LIST "# WARNING! THIS FILE IS AUTOGENERATED. DO NOT EDIT!\n";
    print LIST "#\n";
198 199 200
    if (defined($inituserlist)) {
	print LIST "$inituserlist\n";
    }
201 202

    for ($i = 0; $i < $query_result->numrows; $i++) {
203
	my $user_email = ($query_result->fetchrow_array())[0];
204 205 206
	if (! defined($user_email)) {
	    next;
	}
207 208
	print LIST "$user_email\n";
	print "$user_email\n" if $d;
209 210
    }
    close(LIST);
211

212 213 214 215 216 217 218
    #
    # Fire the new file over to the fileserver to finish up.
    #
    $UID = 0;
    system("$SSH $PROG $progarg < $tempfile") == 0 or
    	fatal("Failed: $SSH $PROG $progarg < $tempfile: $?");
    unlink("$tempfile");
219 220
}

221 222 223 224
#
# Close the lock file. Exiting releases it, but might as well.
#
close(LOCK);
225 226 227 228
exit 0;

sub fatal {
  local($msg) = $_[0];
229
  SENDMAIL($TBOPS, "Failure Generating Email Lists", $msg);
230 231
  die($msg);
}