source: gsdl/trunk/bin/script/schedule.pl@ 16137

Last change on this file since 16137 was 16137, checked in by osborn, 16 years ago

new script to interact with cron scheduler

  • Property svn:executable set to *
File size: 17.3 KB
Line 
1#!/usr/bin/perl -w
2
3###########################################################################
4#
5# schedule.pl --
6# A component of the Greenstone digital library software
7# from the New Zealand Digital Library Project at the
8# University of Waikato, New Zealand.
9#
10# Copyright (C) 1999 New Zealand Digital Library Project
11#
12# This program is free software; you can redistribute it and/or modify
13# it under the terms of the GNU General Public License as published by
14# the Free Software Foundation; either version 2 of the License, or
15# (at your option) any later version.
16#
17# This program is distributed in the hope that it will be useful,
18# but WITHOUT ANY WARRANTY; without even the implied warranty of
19# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20# GNU General Public License for more details.
21#
22# You should have received a copy of the GNU General Public License
23# along with this program; if not, write to the Free Software
24# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25#
26###########################################################################
27
28package schedule;
29
30BEGIN {
31 die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
32 die "GSDLOS not set\n" unless defined $ENV{'GSDLOS'};
33 unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
34 unshift (@INC, "$ENV{'GSDLHOME'}/perllib/cpan");
35 unshift (@INC, "$ENV{'GSDLHOME'}/perllib/plugins");
36 unshift (@INC, "$ENV{'GSDLHOME'}/perllib/plugouts");
37 unshift (@INC, "$ENV{'GSDLHOME'}/perllib/classify");
38
39 if (defined $ENV{'GSDLEXTS'}) {
40 my @extensions = split(/:/,$ENV{'GSDLEXTS'});
41 foreach my $e (@extensions) {
42 my $ext_prefix = "$ENV{'GSDLHOME'}/ext/$e";
43
44 unshift (@INC, "$ext_prefix/perllib");
45 unshift (@INC, "$ext_prefix/perllib/cpan");
46 }
47 }
48}
49
50use strict;
51no strict 'refs';
52no strict 'subs';
53
54use FileHandle;
55use Fcntl;
56use printusage;
57use parse2;
58use parse3;
59use gsprintf 'gsprintf';
60
61
62my $frequency_list =
63 [ { 'name' => "hourly",
64 'desc' => "{schedule.frequency.hourly}" },
65 { 'name' => "daily",
66 'desc' => "{schedule.frequency.daily}" },
67 { 'name' => "weekly",
68 'desc' => "{schedule.frequency.weekly}" }
69 ];
70
71my $action_list =
72 [ { 'name' => "add",
73 'desc' => "{schedule.action.add}" },
74 { 'name' => "update",
75 'desc' => "{schedule.action.update}" },
76 { 'name' => "delete",
77 'desc' => "{schedule.action.delete}" }
78 ];
79
80my $arguments =
81 [
82 { 'name' => "schedule",
83 'desc' => "{schedule.schedule}",
84 'type' => "flag",
85 'reqd' => "no",
86 'modegli' => "3" },
87 { 'name' => "frequency",
88 'desc' => "{schedule.frequency}",
89 'type' => "enum",
90 'list' => $frequency_list,
91 'deft' => "hourly",
92 'reqd' => "no",
93 'modegli' => "4" },
94 { 'name' => "action",
95 'desc' => "{schedule.action}",
96 'type' => "enum",
97 'list' => $action_list,
98 'deft' => "add",
99 'reqd' => "no",
100 'modegli' => "4" },
101 { 'name' => "import",
102 'desc' => "{schedule.import}",
103 'type' => "quotestr",
104 'deft' => "",
105 'reqd' => "yes",
106 'hiddengli' => "yes" },
107 { 'name' => "build",
108 'desc' => "{schedule.build}",
109 'type' => "quotestr",
110 'deft' => "",
111 'reqd' => "yes",
112 'hiddengli' => "yes" },
113 { 'name' => "colname",
114 'desc' => "{schedule.colname}",
115 'type' => "string",
116 'deft' => "",
117 'reqd' => "no",
118 'hiddengli' => "yes" },
119 { 'name' => "xml",
120 'desc' => "{scripts.xml}",
121 'type' => "flag",
122 'reqd' => "no",
123 'hiddengli' => "yes" },
124 { 'name' => "language",
125 'desc' => "{scripts.language}",
126 'type' => "string",
127 'reqd' => "no",
128 'hiddengli' => "yes" },
129 { 'name' => "email",
130 'desc' => "{schedule.email}",
131 'type' => "flag",
132 'reqd' => "no",
133 'modegli' => "4" },
134 { 'name' => "toaddr",
135 'desc' => "{schedule.toaddr}",
136 'type' => "string",
137 'reqd' => "no",
138 'deft' => "",
139 'modegli' => "4" },
140 { 'name' => "fromaddr",
141 'desc' => "{schedule.fromaddr}",
142 'type' => "string",
143 'deft' => "",
144 'reqd' => "no",
145 'modegli' => "4" },
146 { 'name' => "smtp",
147 'desc' => "{schedule.smtp}",
148 'type' => "string",
149 'deft' => "",
150 'reqd' => "no",
151 'modegli' => "4" },
152 { 'name' => "out",
153 'desc' => "{schedule.out}",
154 'type' => "string",
155 'deft' => "STDERR",
156 'reqd' => "no",
157 'hiddengli' => "yes" },
158 { 'name' => "gli",
159 'desc' => "{schedule.gli}",
160 'type' => "flag",
161 'reqd' => "no",
162 'hiddengli' => "yes" }
163 ];
164
165
166my $options = { 'name' => "schedule.pl",
167 'desc' => "Interaction with Cron",
168 'args' => $arguments };
169
170&main();
171
172sub main {
173
174 #params
175 my ($action, $frequency, $import, $build, $colname, $xml, $language,
176 $email, $toaddr, $fromaddr, $smtp, $gli, $out);
177
178 #other vars
179 my ($i,$numArgs,$os,$erase,$erase2,$copy,$newpl,$gsdl,$path,$cronf,
180 $nf,$of,$opf, $cronstr, $ecmd,$ecmd2, $record, $cronrec,$ncronf);
181
182 #some defaults
183 $action = "add";
184 $frequency = "hourly";
185 $import = "";
186 $build = "";
187 $colname = "";
188 $xml = 0;
189 $email = 0;
190 $gli = 0;
191 $language = "";
192 $out = "STDERR";
193
194
195 $gsdl = $ENV{'GSDLHOME'};
196 $os = $ENV{'GSDLOS'};
197 $path = $ENV{'PATH'};
198
199 my $service = "schedule";
200
201 #For this to work, we need to know if -gli exists
202
203 $numArgs=$#ARGV+1;
204 $i = 0;
205 while($i < $numArgs)
206 {
207 if($ARGV[$i] =~ /gli/) {
208 $gli = 1;
209 }
210 $i++;
211 }
212
213 #We are using two different parsers here, because the GLI in linux (and probably darwin) will not take
214 #an entire double-quoted string as an argument, while if schedule.pl is
215 #executed from the command line, the entire double-quoted string is taken
216 #as an argument. For Windows, it seems that it does.
217 my $hashParsingResult = {};
218 my $intArgLeftAfterParsing;
219 if($gli && $os eq "linux") {
220 $intArgLeftAfterParsing = parse3::parse(\@ARGV, $arguments, $hashParsingResult, "allow_extra_options");
221 } else {
222 $intArgLeftAfterParsing = parse2::parse(\@ARGV, $arguments, $hashParsingResult, "allow_extra_options");
223
224 }
225
226 #check for extra options
227 if ($intArgLeftAfterParsing == -1 || $intArgLeftAfterParsing > 0 || (@ARGV && $ARGV[0] =~ /^\-+h/))
228 {
229 &PrintUsage::print_txt_usage($options, "{schedule.params}");
230 die "\n";
231 }
232
233 foreach my $strVariable (keys %$hashParsingResult)
234 {
235 eval "\$$strVariable = \$hashParsingResult->{\"\$strVariable\"}";
236 }
237
238 if ($xml) {
239 &PrintUsage::print_xml_usage($options);
240 print "\n";
241 return;
242
243 }
244
245 if ($gli) { # the gli wants strings to be in UTF-8
246 &gsprintf::output_strings_in_UTF8;
247 }
248
249 if($action eq "add" || $action eq "update") {
250 if($email) {
251 if($smtp eq "" || $toaddr eq "" || $fromaddr eq "" || $smtp =~ /^-/ || $toaddr =~ /^-/ || $fromaddr =~ /^-/) {
252 &gsprintf($out, "{schedule.error.email} \n");
253 die "\n";
254 }
255
256
257 if($import eq "" || $build eq "") {
258 &gsprintf($out, "{schedule.error.importbuild} \n");
259 die "\n";
260 }
261 }
262 }
263 if($colname eq "") {
264 &gsprintf($out, "{schedule.error.colname} \n");
265 die "\n";
266 }
267
268 #not sure if this is always set?
269 #language may be passed in too
270 if($language eq "" && exists($ENV{'GSDLLANG'})) {
271 $language = $ENV{'GSDLLANG'};
272 }
273 elsif($language eq "") {
274 $language = "en";
275 }
276
277 $newpl = "cron.pl";
278 my $logfile = "cron".time().".txt";
279
280 if($action eq "delete") {
281
282 print STDERR "<Delete>\n" if $gli;
283
284 if($os =~ /^linux$/ || $os =~ /^darwin$/) {
285 system("\\rm $gsdl/collect/$colname/$newpl 2>/dev/null");
286 system("\\rm $gsdl/collect/$colname/cronjob 2>/dev/null");
287 } else { #in windows
288
289 system("del $gsdl\\\\collect\\\\$colname\\\\$newpl 2>nul"); #nul is windows equivalent to /dev/null
290
291 }
292
293
294 &gsprintf($out, "{schedule.deleted}\n");
295 }
296 else {
297 #For the Scheduling monitor
298 print STDERR "<Schedule>\n" if $gli;
299
300 if ($os =~ /^linux$/ || $os =~ /^darwin$/) {
301
302 $import = $import." 2>$gsdl/collect/$colname/log/$logfile";
303 $build = $build." 2>>$gsdl/collect/$colname/log/$logfile";
304 $erase = "\\\\rm -r $gsdl/collect/$colname/index 2>>$gsdl/collect/$colname/log/$logfile";
305 $erase2 = "mkdir $gsdl/collect/$colname/index 2>>$gsdl/collect/$colname/log/$logfile";
306 $copy = "mv $gsdl/collect/$colname/building/* $gsdl/collect/$colname/index/ 2>>$gsdl/collect/$colname/log/$logfile";
307 if($email) {
308 #first,we need to add backslashes before the 'at' symbol.
309 $toaddr =~ s/\@/\\\@/g;
310 $fromaddr =~ s/\@/\\\@/g;
311
312 $ecmd = "$gsdl/bin/script/sendmail.pl -to $toaddr -from $fromaddr -smtp $smtp -msgfile $gsdl/collect/$colname/log/$logfile -subject \\\"Results of build for collection $colname\\\" 2>>$gsdl/collect/$colname/log/$logfile >>$gsdl/collect/$colname/log/$logfile";
313
314 $ecmd2 = "$gsdl/bin/script/sendmail.pl -to $toaddr -from $fromaddr -smtp $smtp -msgfile $gsdl/etc/cronlock.txt -subject \\\"Results of build for collection $colname\\\" 2>>$gsdl/collect/$colname/log/$logfile >>$gsdl/collect/$colname/log/$logfile";
315 }
316
317 } else { #in windows
318
319 $gsdl =~ s/\\/\\\\/g;
320 $path =~ s/\\/\\\\/g;
321
322 $import =~ s/\\/\\\\/g;
323 $build =~ s/\\/\\\\/g;
324
325 $import =~ s/exe/exe\\\"/g;
326 $import =~ s/pl/pl\\\"/g;
327 $build =~ s/exe/exe\\\"/g;
328 $build =~ s/pl/pl\\\"/g;
329
330
331 my $prompt = substr($gsdl,0,2);
332
333 $import =~ s/$prompt/\\\"$prompt/g;
334 $build =~ s/$prompt/\\\"$prompt/g;
335
336 #not the best solution - won't work if someone chooses something weird
337 $import =~ s/\\collect/\\collect\\\"/;
338 $build =~ s/\\collect/\\collect\\\"/;
339
340 $import = "$import 2>\\\"$gsdl\\\\collect\\\\$colname\\\\log\\\\$logfile\\\" ";
341 $build = "$build 2>>\\\"$gsdl\\\\collect\\\\$colname\\\\log\\\\$logfile\\\" ";
342
343
344 $erase = "rd \\\/S \\\/Q \\\"$gsdl\\\\collect\\\\$colname\\\\index\\\" 2>>\\\"$gsdl\\\\collect\\\\$colname\\\\log\\\\$logfile\\\" ";
345 $erase2 = "md \\\"$gsdl\\\\collect\\\\$colname\\\\index\\\" 2>>\\\"$gsdl\\\\collect\\\\$colname\\\\log\\\\$logfile\\\" ";
346 $copy = "xcopy \\\/E \\\/Y \\\"$gsdl\\\\collect\\\\$colname\\\\building\\\\*\\\" \\\"$gsdl\\\\collect\\\\$colname\\\\index\\\\\\\" >>\\\"$gsdl\\\\collect\\\\$colname\\\\log\\\\$logfile\\\" ";
347 if($email) {
348 $toaddr =~ s/\@/\\\@/g;
349 $fromaddr =~ s/\@/\\\@/g;
350 $ecmd = "\\\"$gsdl\\\\bin\\\\windows\\\\perl\\\\bin\\\\perl.exe\\\" -S \\\"$gsdl\\\\bin\\\\script\\\\sendmail.pl\\\" -to $toaddr -from $fromaddr -smtp $smtp -msgfile \\\"$gsdl\\\\collect\\\\$colname\\\\log\\\\$logfile\\\" -subject \\\"Results of build for collection $colname\\\" >>\\\"$gsdl\\\\collect\\\\$colname\\\\log\\\\$logfile\\\" ";
351
352 $ecmd2 = "\\\"$gsdl\\\\bin\\\\windows\\\\perl\\\\bin\\\\perl.exe\\\" -S \\\"$gsdl\\\\bin\\\\script\\\\sendmail.pl\\\" -to $toaddr -from $fromaddr -smtp $smtp -msgfile \\\"$gsdl\\\\etc\\\\cronlock.txt\\\" -subject \\\"Results of build for collection $colname\\\" >>\\\"$gsdl\\\\collect\\\\$colname\\\\log\\\\$logfile\\\" ";
353 }
354 }
355
356
357 $nf = new FileHandle() ||
358 (&gsprintf(STDERR, "{common.cannot_open_output_file}: $!\n", $out) && die);
359
360 open($nf, ">$gsdl/collect/$colname/$newpl") ||
361 (&gsprintf(STDERR, "{common.cannot_open_output_file}: $!\n", $out) && die);
362
363
364 print $nf "\#!/usr/bin/perl";
365 print $nf "\n\n";
366
367
368 #we need to set environment variables for import and build
369 print $nf "\$ENV{'GSDLHOME'}=\"$gsdl\"\;\n";
370 print $nf "\$ENV{'GSDLOS'}=\"$os\"\;\n";
371 print $nf "\$ENV{'GSDLLANG'}=\"$language\"\;\n";
372 print $nf "\$ENV{'PATH'}=\"$path\"\;\n";
373
374 if($os =~ /^windows$/) {
375 print $nf "if\(-e \\\"$gsdl\\\\collect\\\\$colname\\\\etc\\\\cron.lck\\\" \"\)\{ \n";
376 } else {
377 print $nf "if\(-e \"$gsdl/collect/$colname/etc/cron.lck\"\) \{ \n";
378 }
379 if($email) {
380 print $nf " system(\"$ecmd2\")\;\n";
381 }
382 else {
383 print $nf " system(\"more \"$gsdl/etc/cronlock.txt\" >\"$gsdl/collect/$colname/log/$logfile\"\"\)\;\n";
384
385 }
386 print $nf "\} else \{\n";
387
388 if($os eq "linux" || $os eq "darwin") {
389 $import =~ s/\"//;
390 $import =~ s/\"//;
391 $build =~ s/\"//;
392 $build =~ s/\"//;
393 }
394
395 if($os =~ /^windows$/) {
396 print $nf "system(\"echo lock \>\\\"$gsdl\\\\collect\\\\$colname\\\\etc\\\\cron.lck\\\"\")\;\n";
397 } else {
398 print $nf "system(\"echo lock >\\\"$gsdl/collect/$colname/etc/cron.lck\\\" \")\;\n";
399 }
400
401 print $nf " system(\"$import\")\;\n";
402 print $nf " system(\"$build\")\;\n";
403
404 print $nf " system(\"$erase\")\;\n";
405 print $nf " system(\"$erase2\")\;\n";
406
407 print $nf " system(\"$copy\")\;\n";
408 if($email) {
409 print $nf " system(\"$ecmd\")\;\n";
410 }
411
412
413 #need to set permissions in linux
414 if($os =~ /^linux$/ || $os =~ /^darwin$/) {
415 print $nf "system(\"chmod -R 755 $gsdl/collect/$colname/index/*\")\;\n";
416 print $nf "system(\"\\\\rm $gsdl/collect/$colname/etc/cron.lck\")\;\n";
417 } else {
418 print $nf "system(\"del \\\"$gsdl\\\\collect\\\\$colname\\\\etc\\\\cron.lck\\\" \")\;\n";
419 }
420
421
422
423 print $nf "\}\n";
424
425 close($nf);
426 if($os =~ /^linux$/ || $os =~ /^darwin$/) {
427 system("chmod 755 $gsdl/collect/$colname/cron.pl");
428 }
429
430 &gsprintf($out, "{schedule.scheduled}\n");
431 }
432
433 #next, we need to create a crontab file. For now, a crontab will be set up
434 #to run at midnight either nightly or weekly.
435 $gsdl =~ s/\\\\/\\/g;
436 if ($os =~ /^linux$/ || $os =~ /^darwin$/)
437 {
438 $cronf="cronjob";
439 open($nf, ">$gsdl/collect/$colname/$cronf") ||
440 (&gsprintf(STDERR, "{common.cannot_open_output_file}: $!\n", $out) && die);
441
442 #see if there is an existing crontab
443 system("crontab -l >$gsdl/collect/$colname/outfile 2>/dev/null");
444
445 $opf = new FileHandle();
446 open($opf, "$gsdl/collect/$colname/outfile") ||
447 (&gsprintf(STDERR, "{common.cannot_open_output_file}: $!\n", $out) && die);
448 $record = <$opf>;
449
450 #if there is an existing crontab file
451 #preserve all records and change existing record for
452 #current collection
453 if ($record)
454 {
455 do
456 {
457 if($record !~ /$colname/)
458 {
459 print $nf $record;
460 }
461 } while($record = <$opf>);
462
463 close($opf);
464 }
465
466
467 if($action =~ /^add$/ || $action =~ /^update$/)
468 {
469 if($frequency eq "hourly") {
470 $cronrec = "50 * * * * $gsdl/collect/$colname/cron.pl";
471 }
472 elsif($frequency eq "daily") {
473 $cronrec = "00 0 * * * $gsdl/collect/$colname/cron.pl";
474 }
475 elsif($frequency eq "weekly") {
476 $cronrec = "59 11 * * 0 $gsdl/collect/$colname/cron.pl";
477 }
478
479 $cronrec = $cronrec." 2>/dev/null\n";
480
481 print $nf $cronrec;
482 }
483
484 close($nf);
485
486 #this makes the cronjob official
487 #still needs to be done for existing records
488 system("crontab $gsdl/collect/$colname/$cronf 2>/dev/null");
489
490 #cleanup
491 system("\\rm $gsdl/collect/$colname/outfile");
492 system("\\rm $gsdl/collect/$colname/$cronf");
493
494 if($action eq "add" || $action eq "update") {
495 &gsprintf($out, "{schedule.cron}\n");
496 }
497
498 } else {
499
500 #for windows, we will put crontab file in the same place. some limitations
501 #1) the absolute path to greenstone cannot have spaces if one is going to do this
502 #2) cron.exe needs to be started manually before doing this
503 #3) greenstone may have to be shut down completely to do this or lock problems occur
504
505 $cronf="crontab"; #pycron.exe expects this filename!
506 $ncronf="crontab.new";
507 #check to see if crontab file exists
508 if(-e "$gsdl/collect/$cronf")
509 {
510
511 open($of, "$gsdl/collect/$cronf") ||
512 (&gsprintf(STDERR, "{common.cannot_open_output_file}: $!\n", $out) && die);
513
514
515 open($nf, ">$gsdl/collect/$ncronf") ||
516 (&gsprintf(STDERR, "{common.cannot_open_output_file}: $!\n", $out) && die);
517
518 while($record = <$of>)
519 {
520 if($record !~ /$colname/)
521 {
522 print $nf $record;
523 }
524 }
525 close($of);
526 close($nf);
527
528 system("del \"$gsdl\\collect\\$cronf\"");
529 system("move \"$gsdl\\collect\\$ncronf\" \"$gsdl\\collect\\$cronf\"");
530
531
532 if($action =~ /^add$/ || $action =~ /^update$/)
533 {
534 open($nf, ">>$gsdl/collect/$cronf") ||
535 (&gsprintf(STDERR, "{common.cannot_open_output_file}: $!\n", $out) && die);
536
537 if($frequency eq "hourly") {
538 print $nf "50 * * * * silentstart.exe $gsdl\\collect\\$colname\\cron.pl\n";
539 }
540 elsif($frequency eq "daily") {
541 print $nf "00 0 * * * silentstart.exe $gsdl\\collect\\$colname\\cron.pl\n";
542 }
543 elsif($frequency eq "weekly") {
544 print $nf "59 11 * * 0 silentstart.exe $gsdl\\collect\\$colname\\cron.pl\n";
545 }
546 close($nf);
547 }
548
549 } else {
550 if($action =~ /^add$/ || $action =~ /^update$/)
551 {
552 open($nf, ">$gsdl/collect/$cronf") ||
553 (&gsprintf(STDERR, "{common.cannot_open_output_file}: $!\n", $out) && die);
554 if($frequency eq "hourly") {
555 print $nf "50 * * * * silentstart.exe $gsdl\\collect\\$colname\\cron.pl\n";
556 }
557 elsif($frequency eq "daily") {
558 print $nf "00 0 * * * silentstart.exe $gsdl\\collect\\$colname\\cron.pl\n";
559 }
560 elsif($frequency eq "weekly") {
561 print $nf "59 11 * * 0 silentstart.exe $gsdl\\collect\\$colname\\cron.pl\n";
562 }
563
564 close($nf);
565 }
566 }
567
568 if($action eq "update" || $action eq "add") {
569 &gsprintf($out, "{schedule.cron}\n");
570 }
571 }
572
573 #For the scheduling monitor
574 print STDERR "<Done>\n" if $gli;
575
576
577
578} #end sub main
Note: See TracBrowser for help on using the repository browser.