ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/JSOC/proj/util/scripts/exportmanage.pl
Revision: 1.20
Committed: Fri Jan 31 16:42:46 2014 UTC (9 years, 7 months ago) by jsoc
Content type: text/plain
Branch: MAIN
CVS Tags: Ver_9-1, Ver_9-2, Ver_8-8, Ver_8-3, Ver_8-6, Ver_8-7, Ver_8-4, Ver_8-5, Ver_8-10, Ver_8-11, Ver_8-12, Ver_9-0
Changes since 1.19: +8 -8 lines
Log Message:
Not sure why this is here, but it looks right.

File Contents

# Content
1 #!/usr/bin/perl
2
3 # Here's how to run this script (from scratch)
4 # ssh jsoc@j0
5 # cd /home/jsoc/exports
6 # rm keep_running
7 # exportmanage.pl -jsocdev procser=jsoc.export_procs &
8 # To start the web version for jsoc.stanford.edu repeat the above but do:
9 # rm keep_running_web
10 # exportmanage.pl -jsocweb procser=jsoc.export_procs&
11 # At some point, I'll add the production version of the script, which
12 # would then be run as "exportmanage.pl -jsocpro &"
13 # To start the debug test version for jsoc2 do:
14 # rm keep_running_test
15 # exportmanage.pl -jsoctest procser=jsoc.export_procs &
16
17 # To test the entire export workflow:
18 # 1. Run export manage like so:
19 # su <USER>
20 # where <USER> is the user whose $PATH contains the paths to the modules/scripts that have new code to be tested.
21 # The manager program makes shell scripts that call programs and scripts by calling the program/script base file
22 # name (not the full path to the program/script). So the actual program/script that runs will be the one
23 # that the shell resolves using the $PATH variable. For example, if the user arta makes
24 # changes to the jsoc_export_as_fits in arta's home directory, and arta's $PATH contains a pointer to the binaries
25 # in arta's home directory, then arta should run 'su arta' before continuing. IMPORTANT - <USER> will need
26 # permissions to write into /home/jsoc/exports/tmp and /home/jsoc/exports/logs. Generally <USER> will be a
27 # member of the group jsoc, so this requirement will be met.
28 # cd /home/jsoc/exports
29 # /home/jsoc/cvs/Development/JSOC/proj/util/scripts/exportmanage.pl -root <ROOT> -dbuser <DBUSER> -dbhost <DBHOST> -manager <MANAGER> -runflag <RFLAG> &
30 # where <ROOT> is the CVS code tree root containing <MANAGER>
31 # and <DBUSER> is the PG user who the manager connects as (defaults to "production"). IMPORTANT - the manager will
32 # write records to tables that require elevated permissions. Most likely, you'll need to connect to the database
33 # as user production to do this. This means that you'll need to place the password for user production in
34 # your .pgpass file.
35 # and <DBHOST> is the host of the database server (defaults to "hmidb"). For internal exports, should be "hmidb", for exports from public db, should be "hmidb2"
36 # and <MANAGER> is the name of the manager program (defaults to "jsoc_export_manage"). IMPORTANT - you should include
37 # a "-t" flag. This will cause the manager program to run in test mode, which means that it will process records
38 # in jsoc.export_new that contain the special test status of 12 (instead of the regular status of 2).
39 # and <RFLAG> is the file flag that keeps this script running in a loop (defaults to keep_running in cdir)
40 #
41 # Example : /home/jsoc/cvs/Development/JSOC/proj/util/scripts/exportmanage.pl -root /home/arta/cvs/JSOC -dbuser production -dbhost hmidb2 -manager "jsoc_export_manage -t procser=jsoc.export_procs" -runflag keepruntest.txt -logflag Test &
42 #
43 # 2. Point a browser at http://jsoc.stanford.edu/ajax/exportdatatest.html and export something.
44
45 use strict;
46 use warnings;
47
48 use FileHandle;
49 use Fcntl ':flock';
50 use FindBin qw($RealBin);
51 use lib "$RealBin/../../../localization";
52 use drmsparams;
53
54 use constant kExportDir => "/home/jsoc/exports";
55 # use constant kMailList => "arta\@sun.stanford.edu jeneen\@sun.stanford.edu phil\@sun.stanford.edu";
56 use constant kMailList => "arta\@sun.stanford.edu";
57 use constant kMailMessage1 => "exportmanage.pl could not start jsoc_export_manage. This is a critical failure.\nYou should probably contact Art, who was also notified and should respond shortly.\n";
58 use constant kMailMessage2 => "jsoc_export_manage died in response to an unhandled signal (e.g., a segfault).\n";
59 use constant kMailMessage3 => "Could not open log export-daemon log file for writing.\nThis is not a critical failure, but we should\nfix this so that we can track-down future export problems more easily.\nContact Art.\n";
60
61 use constant kMsgType1 => "msgtype1";
62 use constant kMsgType2 => "msgtype2";
63 use constant kMsgType3 => "msgtype3";
64
65 use constant kMsgQInterval => 600; # 10 minutes, at least, between message inserts
66 use constant kMsgQSendInterval => 120; # 2 minutes between mailing of messages
67
68 use constant kLogFlagInt => "Int";
69 use constant kLogFlagExt => "Ext";
70
71 my($config) = new drmsparams;
72
73 my($kINTERNALFLAG) = "/home/jsoc/exports/keep_running";
74 my($kWEBFLAG) = "/home/jsoc/exports/keep_running_web";
75 my($kTESTFLAG) = "/home/jsoc/exports/keep_running_test";
76 #
77 my($kJSOCDEV_ROOT) = "/home/jsoc/cvs/Development/JSOC";
78 my($kJSOCDEV_DBUSER) = "production";
79 my($kJSOCDEV_DBNAME) = $config->get('DBNAME');
80 my($kJSOCDEV_DBHOST) = $config->get('SERVER');
81 my($kJSOCDEV_MANAGE) = "jsoc_export_manage";
82 use constant kProcInfoSeriesDev => "jsoc.export_procs";
83 #
84 my($kJSOCPRO_ROOT) = "/home/jsoc/cvs/JSOC";
85 my($kJSOCPRO_DBUSER) = "production";
86 my($kJSOCPRO_DBNAME) = $config->get('DBNAME');
87 my($kJSOCPRO_DBHOST) = $config->get('SERVER');
88 my($kJSOCPRO_MANAGE) = "jsoc_export_manage";
89 use constant kProcInfoSeriesPro => "jsoc.export_procs";
90 #
91 my($kJSOCWEB_ROOT) = "/home/jsoc/cvs/Development/JSOC";
92 my($kJSOCWEB_DBUSER) = "production";
93 my($kJSOCWEB_DBNAME) = "jsoc";
94 my($kJSOCWEB_DBHOST) = "hmidb2";
95 my($kJSOCWEB_MANAGE) = "jsoc_export_manage";
96 use constant kProcInfoSeriesWeb => "jsoc.export_procs";
97 #
98 my($kJSOCTEST_ROOT) = "/home/jsoc/cvs/Development/JSOC";
99 my($kJSOCTEST_DBUSER) = "phil";
100 my($kJSOCTEST_DBNAME) = $config->get('DBNAME');
101 my($kJSOCTEST_DBHOST) = $config->get('SERVER');
102 my($kJSOCTEST_MANAGE) = "jsoc_export_manage_test";
103 use constant kProcInfoSeriesTst => "jsoc.export_procs";
104
105 my($runningflag) = $kINTERNALFLAG;
106 my($arg);
107 my($root);
108 my($dbhost) = $config->get('SERVER');
109 my($dbname) = $config->get('DBNAME');
110 my($dbuser) = "production";
111 my($binpath);
112 my($manage) = "jsoc_export_manage";
113 my($logfile);
114 my($daemonlog);
115 my($lckfh);
116 my($msg);
117 my($logflag);
118 my($procser);
119
120 while ($arg = shift(@ARGV))
121 {
122 if ($arg eq "-root")
123 {
124 $root = shift(@ARGV);
125 $binpath = "$root/bin";
126 }
127 elsif ($arg eq "-dbhost")
128 {
129 $dbhost = shift(@ARGV);
130 }
131 elsif ($arg eq "-dbuser")
132 {
133 $dbuser = shift(@ARGV);
134 }
135 elsif ($arg eq "-dbname")
136 {
137 $dbname = shift(@ARGV);
138 }
139 elsif ($arg eq "-manager")
140 {
141 $manage = shift(@ARGV);
142 }
143 elsif ($arg eq "-runflag")
144 {
145 $runningflag = shift(@ARGV);
146 }
147 elsif ($arg eq "-logflag")
148 {
149 $logflag = shift(@ARGV);
150 }
151 elsif ($arg eq "-procser")
152 {
153 $procser = shift(@ARGV);
154 }
155 elsif ($arg eq "-jsocdev")
156 {
157 $root = $kJSOCDEV_ROOT;
158 $binpath = "$root/bin";
159 $dbuser = $kJSOCDEV_DBUSER;
160 $dbname = $kJSOCDEV_DBNAME;
161 $dbhost = $kJSOCDEV_DBHOST;
162 $manage = $kJSOCDEV_MANAGE;
163 $runningflag = $kINTERNALFLAG;
164 $logflag = kLogFlagInt;
165 $procser = &kProcInfoSeriesDev;
166 }
167 elsif ($arg eq "-jsocpro")
168 {
169 $root = $kJSOCPRO_ROOT;
170 $binpath = "$root/bin";
171 $dbuser = $kJSOCPRO_DBUSER;
172 $dbname = $kJSOCPRO_DBNAME;
173 $dbhost = $kJSOCPRO_DBHOST;
174 $manage = $kJSOCPRO_MANAGE;
175 $runningflag = $kINTERNALFLAG;
176 $logflag = kLogFlagInt;
177 $procser = &kProcInfoSeriesPro;
178 }
179 elsif ($arg eq "-jsocweb")
180 {
181 $root = $kJSOCWEB_ROOT;
182 $binpath = "$root/bin";
183 $dbuser = $kJSOCWEB_DBUSER;
184 $dbname = $kJSOCWEB_DBNAME;
185 $dbhost = $kJSOCWEB_DBHOST;
186 $manage = $kJSOCWEB_MANAGE;
187 $runningflag = $kWEBFLAG;
188 $logflag = kLogFlagExt;
189 $procser = &kProcInfoSeriesWeb;
190 }
191 elsif ($arg eq "-jsoctest")
192 {
193 $root = $kJSOCTEST_ROOT;
194 $binpath = "$root/bin";
195 $dbuser = $kJSOCTEST_DBUSER;
196 $dbname = $kJSOCTEST_DBNAME;
197 $dbhost = $kJSOCTEST_DBHOST;
198 $manage = $kJSOCTEST_MANAGE;
199 $runningflag = $kTESTFLAG;
200 $logflag = "Test";
201 $procser = &kProcInfoSeriesTst;
202 }
203 }
204
205 # Only run on j0.Stanford.EDU
206 # if ($ENV{HOSTNAME} ne "j0.Stanford.EDU") {
207 # die "I will only run on j0.Stanford.EDU\n";
208 #}
209
210 # Don't run if somebody is already managing the export
211 $lckfh = FileHandle->new(">$runningflag.lck");
212 unless (flock($lckfh, LOCK_EX|LOCK_NB))
213 {
214 print "$0 is already running. Exiting.\n";
215 exit(1);
216 }
217
218 #if (-e $runningflag)
219 #{
220 # die "Can't manage export; another process is already managing it.\n";
221 #}
222
223 if (defined($binpath))
224 {
225 $binpath = "$binpath/$ENV{\"JSOC_MACHINE\"}";
226 }
227 else
228 {
229 $binpath = "";
230 }
231
232 #local $ENV{"PATH"} = "$binpath:$ENV{\"PATH\"}";
233 #local $ENV{"PATH"} = "$scrpath:$ENV{\"PATH\"}";
234 local $ENV{"JSOCROOT"} = $root;
235 local $ENV{"JSOC_DBUSER"} = $dbuser;
236 local $ENV{"JSOC_DBNAME"} = $dbname;
237
238 #`touch $runningflag`;
239 `echo $$ > $runningflag`;
240 $logfile = kExportDir . "/logs/" . `date +"%F_%R.log"`;
241 open(LOG, ">> $logfile") || die "Couldn't open logfile '$logfile'.\n";
242 $daemonlog = kExportDir . "/logs/exportlog${logflag}.txt";
243
244 my($datenow) = `date`;
245 chomp($datenow);
246 $msg = "Started by $ENV{'USER'} at $datenow on machine $ENV{'HOST'} using $dbhost.\n";
247 print LOG $msg;
248
249 my($rout);
250 my($cmd);
251 my($dlogfh);
252 my($err) = 0;
253
254 unless (GetDLogFH(\$dlogfh, $daemonlog))
255 {
256 print $dlogfh $msg;
257 CloseDLog(\$dlogfh);
258 }
259
260 $cmd = "$binpath/$manage JSOC_DBHOST=$dbhost procser=$procser";
261
262 my($msgq) = {lastsend => time(), msgs => {}};
263
264 while (1)
265 {
266 # print "running $cmd.\n";
267 $rout = qx($cmd 2>&1);
268
269 if ($? == -1)
270 {
271 QueueMessage($msgq, &kMsgType1, "Export Daemon Execution Failure!!", &kMailMessage1);
272 }
273 elsif ($? & 127)
274 {
275 # jsoc_export_manage died in response to an unhandled signal
276 my($sig) = $? & 127;
277
278 QueueMessage($msgq, &kMsgType1, "Export Daemon Execution Failure!!", &kMailMessage2, "DB Host: $dbhost\n", "Unhandled signal: $sig.\n");
279 }
280 elsif (($? >> 8) != 0)
281 {
282 # jsoc_export_manage returned with an error code
283 $msg = "$manage returned with a non-zero code of $? >> 8.\n";
284 unless (GetDLogFH(\$dlogfh, $daemonlog))
285 {
286 print $dlogfh $msg;
287 }
288
289 print LOG $msg;
290 }
291
292 if (defined($rout) && length($rout) > 0)
293 {
294 $msg = "$rout\n";
295 unless (GetDLogFH(\$dlogfh, $daemonlog))
296 {
297 print $dlogfh $msg;
298 }
299
300 print LOG $msg;
301 }
302
303 SendPendingMessages($msgq);
304
305 CloseDLog(\$dlogfh);
306
307 if (KeepRunning($runningflag))
308 {
309 sleep(2);
310 }
311 else
312 {
313 last;
314 }
315 }
316
317 $msg = "Stopped by $ENV{'USER'} at " . `date` . ".\n";
318 unless (GetDLogFH(\$dlogfh, $daemonlog))
319 {
320 print $dlogfh $msg;
321 CloseDLog(\$dlogfh);
322 }
323
324 print LOG $msg;
325 close(LOG);
326
327 # Don't leave junk laying about
328 CleanRunFlag($runningflag);
329
330 # release the exclusive file lock
331 flock($lckfh, LOCK_UN);
332 $lckfh->close;
333
334 exit($err);
335
336 # END
337 sub IOwnRunFlag
338 {
339 my($file) = $_[0];
340 my($fexists);
341 my($iownit);
342 my($line);
343
344 $fexists = (-e $file);
345 if ($fexists)
346 {
347 if (open(FLFILE, "<$file"))
348 {
349 $line = <FLFILE>;
350 chomp($line);
351 $iownit = ($line == $$);
352 close(FLFILE);
353 }
354 }
355
356 return $fexists && $iownit;
357 }
358
359 sub KeepRunning
360 {
361 my($file) = $_[0];
362
363 return IOwnRunFlag($file)
364 }
365
366 sub CleanRunFlag
367 {
368 my($file) = $_[0];
369
370 if (IOwnRunFlag($file))
371 {
372 unlink($file);
373 }
374 }
375
376 sub GetDLogFH
377 {
378 my($rfh) = shift; # reference to filehandle object
379 my($dlog) = shift;
380 my($msgq) = shift;
381 my($err);
382
383 $err = 0;
384
385 if (!defined($$rfh))
386 {
387 $$rfh = FileHandle->new(">>$dlog");
388
389 if (!defined($$rfh))
390 {
391 QueueMessage($msgq, &kMsgType1, "Export Daemon Log Unavailable", &kMailMessage3);
392 $err = 1;
393 }
394 }
395
396 return $err;
397 }
398
399 sub CloseDLog
400 {
401 my($rfh) = $_[0]; # reference to filehandle object
402
403 if (defined($$rfh))
404 {
405 $$rfh->close();
406 undef($$rfh);
407 }
408 }
409
410 sub SendPendingMessages
411 {
412 my($msgs) = shift;
413 my($imsg);
414 my($msg);
415 my($subj);
416
417 if (time() - $msgs->{lastsend} > &kMsgQSendInterval)
418 {
419 # Check for pending messages
420 foreach $imsg (keys(%{$msgq->{msgs}}))
421 {
422 $msg = $msgq->{msgs}->{$imsg}->{msg};
423 $subj = $msgq->{msgs}->{$imsg}->{subj};
424 open(MAILPIPE, "| /bin/mail -s \"$subj\" " . &kMailList) || die "Couldn't open 'mail' pipe.\n";
425 print MAILPIPE $msg;
426 close(MAILPIPE);
427
428 if ($msgq->{msgs}->{$imsg}->{ntimes} > 1)
429 {
430 $msgq->{msgs}->{$imsg}->{ntimes} = $msgq->{msgs}->{$imsg}->{ntimes} - 1;
431 }
432 else
433 {
434 delete($msgq->{msgs}->{$imsg});
435 }
436 }
437
438 $msgs->{lastsend} = time();
439 }
440 }
441
442 # Message queue:
443 # key - id
444 # val - hash : {instime => 10292392, msg => "export failure", ntimes => 5}
445 # where instime is unix seconds identifying time message was inserted into queue.
446 # subj is the mail subject
447 # msg is the message to mail
448 # ntimes is the number of times to send message out.
449 sub QueueMessage
450 {
451 my($msgq) = shift;
452 my($type) = shift;
453 my($subj) = shift;
454 my(@msg) = @_;
455 my($oktoins);
456
457 if (exists($msgq->{msgs}->{$type}))
458 {
459 $oktoins = time() - $msgq->{msgs}->{$type}->{instime} > &kMsgQInterval;
460
461 # Message already exists. Don't add to queue until some time elapses.
462 if ($oktoins)
463 {
464 $msgq->{msgs}->{$type}->{ntimes} = $msgq->{msgs}->{$type}->{ntimes} + 1;
465 }
466 }
467 else
468 {
469 my($msgstr) = join('', @msg);
470 $msgq->{msgs}->{$type} = {instime => time(), subj => $subj, msg => $msgstr, ntimes => 1};
471 }
472 }
473
474 __DATA__