ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/COMP/JOBROBOT/TaskSource
Revision: 1.37
Committed: Fri Oct 23 12:43:08 2009 UTC (15 years, 6 months ago) by asciaba
Branch: MAIN
Changes since 1.36: +10 -6 lines
Log Message:
Changes to send jobs to a specific site instead of close to a specific SE

File Contents

# User Rev Content
1 gutsche 1.1 #!/usr/bin/env perl
2    
3     ##H This drop box agent initiates tasks on all published datasets.
4     ##H A task is an application to run on a dataset at a particular site.
5     ##H It keeps a record of tasks created and avoids submitting a task too
6     ##H frequently.
7     ##H
8     ##H Usage:
9     ##H
10 gutsche 1.21 ##H TaskSource
11     ##H
12     ##H -state agent state directory, including inbox
13     ##H -next next agent to pass the drops to; can be given several times
14     ##H -wait time to wait in seconds between work scans
15     ##H -sec_between_inits seconds between submission of same dataset/tier combination
16     ##H -siteconfig file with list of valid SE and their schedule limits
17 gutsche 1.25 ##H -dbsdlspath path to DBS/DLS discovery ascii files
18 gutsche 1.21 ##H -max-site-queue default value for maximum events scheduled per site
19 gutsche 1.22 ##H -max-jobs maximum number of jobs per project, -1 to deactivate
20 gutsche 1.21 ##H -scheduler scheduler
21     ##H -events number of events per job
22     ##H -pattern DBS discovery pattern
23     ##H -validtiers perl string pattern with valid tiers (DIGI|RECO)
24 asciaba 1.32 ##H -cmssw CMSSW directory to use for CRAB
25 gutsche 1.21 ##H -simcfg CMSSW parameter-set for tier SIM
26     ##H -simoutput putput (comma separated) for tier SIM
27     ##H -digicfg CMSSW parameter-set for tier DIGI
28     ##H -digioutput putput (comma separated) for tier DIGI
29     ##H -recocfg CMSSW parameter-set for tier RECO
30     ##H -recooutput putput (comma separated) for tier RECO
31 belforte 1.27 ###H -gencfg CMSSW parameter-set for tier GEN
32     ###H -genoutput putput (comma separater) for tier GEN
33 gutsche 1.1
34     BEGIN {
35     use strict; use warnings; $^W=1;
36     our $me = $0; $me =~ s|.*/||;
37     our $home = $0; $home =~ s|/[^/]+$||; $home ||= "."; $home .= "/../PHEDEX/Toolkit/Common";
38     unshift(@INC, $home);
39     }
40    
41     ######################################################################
42     use UtilsHelp;
43 gutsche 1.21 my %args = (WAITTIME => 600, SECS_PER_EVENT => 1., MAX_SITE_QUEUE => 10);
44     while (scalar @ARGV) {
45     if ($ARGV[0] eq '-state' && scalar @ARGV > 1) {
46     shift (@ARGV); $args{DROPDIR}= shift(@ARGV);
47     } elsif ($ARGV[0] eq '-next' && scalar @ARGV > 1) {
48     shift (@ARGV); push (@{$args{NEXTDIR}}, shift(@ARGV));
49     } elsif ($ARGV[0] eq '-wait' && scalar @ARGV > 1) {
50     shift (@ARGV); $args{WAITTIME} = shift(@ARGV);
51     } elsif ($ARGV[0] eq '-secs_between_inits' && scalar @ARGV > 1) {
52     shift (@ARGV); $args{SECS_BETWEEN_INITS} = shift(@ARGV);
53     } elsif ($ARGV[0] eq '-siteconfig' && scalar @ARGV > 1) {
54     shift (@ARGV); $args{SITECONFIG} = shift(@ARGV);
55 gutsche 1.25 } elsif ($ARGV[0] eq '-dbsdlspath' && scalar @ARGV > 1) {
56     shift (@ARGV); $args{DBSDLSPATH} = shift(@ARGV);
57 gutsche 1.21 } elsif ($ARGV[0] eq '-max-site-queue' && scalar @ARGV > 1) {
58     shift (@ARGV); $args{MAX_SITE_QUEUE} = shift(@ARGV);
59 gutsche 1.22 } elsif ($ARGV[0] eq '-max-jobs' && scalar @ARGV > 1) {
60     shift (@ARGV); $args{MAX_JOBS} = shift(@ARGV);
61 gutsche 1.21 } elsif ($ARGV[0] eq '-scheduler' && scalar @ARGV > 1) {
62     shift (@ARGV); $args{SCHEDULER} = shift(@ARGV);
63     } elsif ($ARGV[0] eq '-events' && scalar @ARGV > 1) {
64     shift (@ARGV); $args{EVENTS} = shift(@ARGV);
65     } elsif ($ARGV[0] eq '-pattern' && scalar @ARGV > 1) {
66     shift (@ARGV); $args{PATTERN} = shift(@ARGV);
67     } elsif ($ARGV[0] eq '-validtiers' && scalar @ARGV > 1) {
68     shift (@ARGV); $args{VALIDTIERS} = shift(@ARGV);
69 asciaba 1.32 } elsif ($ARGV[0] eq '-cmssw' && scalar @ARGV > 1) {
70     shift (@ARGV); $args{CMSSW} = shift(@ARGV);
71 gutsche 1.21 } elsif ($ARGV[0] eq '-simcfg' && scalar @ARGV > 1) {
72     shift (@ARGV); $args{SIMCFG} = shift(@ARGV);
73     } elsif ($ARGV[0] eq '-simoutput' && scalar @ARGV > 1) {
74     shift (@ARGV); $args{SIMOUTPUT} = shift(@ARGV);
75     } elsif ($ARGV[0] eq '-digicfg' && scalar @ARGV > 1) {
76     shift (@ARGV); $args{DIGICFG} = shift(@ARGV);
77     } elsif ($ARGV[0] eq '-digioutput' && scalar @ARGV > 1) {
78     shift (@ARGV); $args{DIGIOUTPUT} = shift(@ARGV);
79     } elsif ($ARGV[0] eq '-recocfg' && scalar @ARGV > 1) {
80     shift (@ARGV); $args{RECOCFG} = shift(@ARGV);
81     } elsif ($ARGV[0] eq '-recooutput' && scalar @ARGV > 1) {
82     shift (@ARGV); $args{RECOOUTPUT} = shift(@ARGV);
83 belforte 1.31 } elsif ($ARGV[0] eq '-usercfg' && scalar @ARGV > 1) {
84     shift (@ARGV); $args{USERCFG} = shift(@ARGV);
85     } elsif ($ARGV[0] eq '-useroutput' && scalar @ARGV > 1) {
86     shift (@ARGV); $args{USEROUTPUT} = shift(@ARGV);
87 belforte 1.27 } elsif ($ARGV[0] eq '-gencfg' && scalar @ARGV > 1) {
88     shift (@ARGV); $args{GENCFG} = shift(@ARGV);
89     } elsif ($ARGV[0] eq '-genoutput' && scalar @ARGV > 1) {
90     shift (@ARGV); $args{GENOUTPUT} = shift(@ARGV);
91 gutsche 1.21 } elsif ($ARGV[0] eq '-h') {
92     &usage();
93     } else {
94     last;
95     }
96 gutsche 1.1 }
97    
98 gutsche 1.21 if (@ARGV || !$args{DROPDIR}) {
99     die "Insufficient parameters, use -h for help.\n";
100 gutsche 1.1 }
101    
102     (new TaskSource (%args))->process();
103    
104     ######################################################################
105     # Routines specific to this agent.
106     package TaskSource; use strict; use warnings; use base 'UtilsAgent';
107     use File::Path;
108     use UtilsCommand;
109     use UtilsLogging;
110     use UtilsTiming;
111     use UtilsNet;
112     use POSIX;
113    
114     sub new
115 gutsche 1.21 {
116 gutsche 1.1 my $proto = shift;
117     my $class = ref($proto) || $proto;
118     my $self = $class->SUPER::new(@_);
119 gutsche 1.21 my %params = (MAX_SITE_QUEUE => undef, # max number of jobs per site
120 gutsche 1.22 MAX_JOBS => undef, # max number of jobs per project, -1 to deactivate
121 gutsche 1.21 SECS_BETWEEN_INITS => 600, # path to siteconfig file
122     SITECONFIG => undef, # path to siteconfig file
123 gutsche 1.25 DBSDLSPATH => "", # path to DBSDLS discovery ascii files
124 gutsche 1.21 EVENTS => 1000, # number of events per job
125     PATTERN => "*", # DBS discovery pattern
126     VALIDTIERS => undef, # perl string pattern with valid tiers (DIGI|RECO)
127 asciaba 1.32 CMSSW => "_none_", # CMSSW directory to use
128 gutsche 1.21 SIMCFG => undef, # CMSSW parameter-set for SIM tier
129     DIGICFG => undef, # CMSSW parameter-set for DIGI tier
130     RECOCFG => undef, # CMSSW parameter-set for RECO tier
131 belforte 1.31 USERCFG => undef, # CMSSW parameter-set for USER tier
132 belforte 1.27 GENCFG => undef, # CMSSW parameter-set for GEN tier
133 gutsche 1.21 SIMOUTPUT => undef, # output (comma separated) for SIM tier
134     DIGIOUTPUT => undef, # output (comma separated) for DIGI tier
135     RECOOUTPUT => undef, # output (comma separated) for RECO tier
136 belforte 1.31 USEROUTPUT => undef, # output (comma separated) for USER tier
137 belforte 1.27 GENOUTPUT => undef, # output (comma separated) for GEN tier
138 gutsche 1.21 SCHEDULER => "edg"); # standard scheduler
139 gutsche 1.1 my %args = (@_);
140     map { $self->{$_} = defined $args{$_} ? $args{$_} : $params{$_} } keys %params;
141     bless $self, $class;
142     return $self;
143 gutsche 1.21 }
144 gutsche 1.1
145     sub init
146 gutsche 1.21 {
147 gutsche 1.1 my ($self) = @_;
148     $self->{TASKREPO} = "$self->{DROPDIR}/tasks";
149     -d "$self->{TASKREPO}"
150 gutsche 1.21 || mkdir "$self->{TASKREPO}"
151 gutsche 1.1 || die "$self->{TASKREPO}: cannot create directory: $!\n";
152    
153     # Determine if links supports -dump-width option
154     $self->{LINKS_OPTS} = [];
155     open (LINKS_HELP, "links -help 2>/dev/null |");
156 gutsche 1.4 if ( grep(/-no-numbering/, <LINKS_HELP>) ) {
157     push(@{$self->{LINKS_OPTS}}, qw(-dump-width 300 -no-numbering 1));
158     } elsif ( grep(/-dump-width/, <LINKS_HELP>) ) {
159     push(@{$self->{LINKS_OPTS}}, qw(-dump-width 300));
160 gutsche 1.1 }
161     close (LINKS_HELP);
162 gutsche 1.21 }
163 gutsche 1.1
164     # Find out how many jobs are pending for each site. This is
165     # insensitive to the job type, and we only check once in the
166     # beginning to avoid favouring one dataset over another --
167     # once we decide to proceed for a site, we submit jobs for
168     # all datasets.
169     sub getSiteStatus
170 gutsche 1.18 {
171 gutsche 1.1 my ($self) = @_;
172     my %result = ();
173     my $taskrepo = $self->{TASKREPO};
174 gutsche 1.21 foreach my $site (<$taskrepo/*/*>) {
175     my ($sitename) = ($site =~ m|.*/(.*)|);
176     foreach my $d (<$site/*/*>) {
177 belforte 1.34 next if (-f "$d/TASK_FINISHED.txt");
178 gutsche 1.21 if (! -f "$d/JOB_CREATE_LOG.txt") {
179     $result{$sitename}{C} ||= 0;
180     $result{$sitename}{C}++;
181     next;
182     }
183 gutsche 1.18
184 gutsche 1.21 my $f = (<$d/crab_*/share/db/jobs>)[0];
185     next if ! defined $f;
186 gutsche 1.18
187 gutsche 1.21 foreach my $status (split(/\n/, &input($f) || '')) {
188     my @statusarray = split('\|', $status);
189     $result{$sitename}{$statusarray[1]} ||= 0;
190     $result{$sitename}{$statusarray[1]}++;
191     }
192 gutsche 1.18 }
193 gutsche 1.21 }
194 gutsche 1.1 return %result;
195 gutsche 1.18 }
196 gutsche 1.1
197 gutsche 1.21 sub createHashFromString
198     {
199     my ($self, $string) = @_;
200     my $cmd = "mktemp /tmp/hash_XXXXXX";
201     open (HASHFILE, "$cmd 2>/dev/null |") or die "cannot run `$cmd': $!\n";
202     my $hash_file_name;
203     foreach my $hash_line (split(/\n/, <HASHFILE> || '')) {
204     chomp($hash_line);
205     $hash_file_name = $hash_line;
206     }
207     $cmd = "echo $string >> $hash_file_name";
208     system $cmd;
209     # open (FILLHASHFILE, "$cmd 2>/dev/null |") or die "cannot run `$cmd': $!\n";
210     $cmd = "cksum $hash_file_name";
211     open (CKSUMHASHFILE, "$cmd 2>/dev/null |") or die "cannot run `$cmd': $!\n";
212     my ($hash, $dummy_one, $dummy_two);
213     foreach my $hash_output (split(/\n/, <CKSUMHASHFILE> || '')) {
214     chomp($hash_output);
215 asciaba 1.33 ($hash, $dummy_one, $dummy_two) = split(/\s+/,$hash_output);
216 gutsche 1.21 }
217     $cmd = "rm -f $hash_file_name";
218     system $cmd;
219     # open (RMHASHFILE, "$cmd 2>/dev/null |") or die "cannot run `$cmd': $!\n";
220    
221     return $hash;
222     }
223    
224 gutsche 1.1 sub idle
225     {
226 gutsche 1.21 &logmsg ("DBS/DLS discovery");
227 gutsche 1.1 my ($self, @pending) = @_;
228     eval {
229     # Get status of how busy the sites are. We obtain this only once
230     # in order to not favour datasets "early on" in the list.
231     my %sitestats = $self->getSiteStatus ();
232 gutsche 1.21 if (keys %sitestats) {
233     my @load;
234     foreach my $site (sort keys %sitestats) {
235 belforte 1.31 my $running = ($sitestats{$site}{R} || 0);
236 asciaba 1.35 my $submitted = ($sitestats{$site}{B} || 0);
237 belforte 1.31 my $scheduled = ($sitestats{$site}{S} || 0);
238     my $created = ($sitestats{$site}{C} || 0);
239 asciaba 1.35 my $pending = $created + $submitted + $scheduled + $running;
240 gutsche 1.21 push (@load, "$site" . join("", map { " $_=$sitestats{$site}{$_}" }
241 belforte 1.31 sort keys %{$sitestats{$site}}) . " L=$pending");
242 gutsche 1.1 }
243 gutsche 1.21 &logmsg ("current load: ", join ("; ", @load));
244     }
245 gutsche 1.1
246 gutsche 1.25 # DBS/DLS discovery
247     # if ascii DBS/DLS discovery file exists in DBSDLSPATH with name: dlsdls_query_$cleaned_pattern.txt
248     # where cleaned pattern is the pattern with / replaced by _
249     # take ascii file, otherwise do discovery
250     my $cleaned_pattern = $self->{PATTERN};
251     $cleaned_pattern =~ s/\//_/g;
252     my $patternfile = $self->{DBSDLSPATH} . "/dbsdls_query_" . $cleaned_pattern . ".txt";
253     if ( -e "$patternfile" ) {
254     &logmsg("Use DBS/DLS ascii file: $patternfile");
255     open (PUBLISHED,"< $patternfile");
256     } else {
257 marcelo 1.28 my $cmd = $ENV{PYTHONSCRIPT} . "/DBS2DLSQuery.py --pattern \"$self->{PATTERN}\"";
258 gutsche 1.25 open (PUBLISHED, "$cmd 2>/dev/null |") or die "cannot run `$cmd': $!\n";
259     }
260 gutsche 1.21 while (<PUBLISHED>) {
261     chomp;
262     &timeStart($self->{STARTTIME});
263 asciaba 1.37 my $sitese;
264 asciaba 1.32 my ($datapath, $site, $totalevents, $events, $secsinit, $cmssw,
265 asciaba 1.33 $mycfg) = split(/\s+/, $_);
266 gutsche 1.21 # read in siteconfig dynamically
267     if ( $self->{SITECONFIG} ) {
268     open(siteconfig_file,"$self->{SITECONFIG}");
269     my @line_array = <siteconfig_file>;
270     my $validsites = "(";
271     for (my $i = 0; $i < scalar @line_array; ++$i) {
272     if (defined $line_array[$i] ) {
273     if ( $line_array[$i] !~ /^#/ && $line_array[$i] !~ /^\n/ ) {
274 asciaba 1.33 my ($tempsite, $tempshortsite, $templimit) = split(/\s+/,$line_array[$i]);
275 gutsche 1.21 chomp($tempsite);
276 asciaba 1.37 chomp($tempshortsite);
277     $sitese = $tempsite if ($site =~ /$tempshortsite/);
278     $validsites = $validsites . $tempshortsite . "|";
279 gutsche 1.19 }
280     }
281 gutsche 1.5 }
282 gutsche 1.21 chop($validsites);
283     $validsites = $validsites . ")";
284     close siteconfig_file;
285 gutsche 1.24 if ( $validsites eq ")" ) {
286     next;
287     } else {
288     next if ($validsites && $site !~ /$validsites/);
289     }
290 gutsche 1.5 }
291 asciaba 1.32 # if defined use number of events per job from pattern file
292     $events ||= $self->{EVENTS};
293     $secsinit ||= $self->{SECS_BETWEEN_INITS};
294     $cmssw ||= $self->{CMSSW};
295     $mycfg ||= "";
296 gutsche 1.22 # check if totalevents is larger than $EVENTS * $MAX_JOBS
297     if ($self->{MAX_JOBS} != -1) {
298 asciaba 1.32 if ( $self->{MAX_JOBS} * $events < $totalevents ) {
299     $totalevents = $self->{MAX_JOBS} * $events;
300 gutsche 1.22 }
301     }
302 asciaba 1.37 $self->createTask($datapath, $site, $sitese, $totalevents, $events,
303 asciaba 1.32 $secsinit, $cmssw, $mycfg, %sitestats);
304 gutsche 1.1 }
305     };
306     do { chomp ($@); &alert ($@); } if $@;
307    
308     $self->nap ($self->{WAITTIME});
309     }
310    
311     sub createTask()
312     {
313 corvo 1.3 my ($self) = shift(@_);
314 asciaba 1.37 my ($datasetpath, $site, $sitese, $totalevents, $events, $secsinit,
315 asciaba 1.32 $cmssw, $mycfg, %sitestats) = @_;
316 gutsche 1.5
317 marcelo 1.28 # Line changed for supporting the DBS2 name format.
318     #my($n, $dataset, $tier, $owner) = split(/\//, $datasetpath);
319     my($n, $dataset, $owner, $comp_tier) = split(/\//, $datasetpath);
320 asciaba 1.33 my($tier) = (split(/-/, $comp_tier))[-1] || $comp_tier;
321 gutsche 1.5
322 gutsche 1.21 # filter on tier
323     next if ($self->{VALIDTIERS} && $tier !~ /$self->{VALIDTIERS}/);
324    
325     my ($cfg, $output);
326 asciaba 1.32 if ($mycfg) {
327     $cfg = $mycfg;
328 gutsche 1.21 } else {
329 asciaba 1.32 if ($tier =~ /RECO/) {
330     $cfg = $self->{RECOCFG};
331     $output = $self->{RECOOUTPUT};
332     } elsif ($tier =~ /USER/) {
333     $cfg = $self->{USERCFG};
334     $output = $self->{USEROUTPUT};
335     } elsif ($tier =~ /DIGI/) {
336     $cfg = $self->{DIGICFG};
337     $output = $self->{DIGIOUTPUT};
338     } elsif ($tier =~ /SIM/) {
339     $cfg = $self->{SIMCFG};
340     $output = $self->{SIMOUTPUT};
341     } elsif ($tier =~ /GEN/) {
342     $cfg = $self->{GENCFG};
343     $output = $self->{GENOUTPUT};
344     } else {
345     &logmsg ("No valid tier, defaults for cfg and output");
346     $cfg = "robot.cfg";
347     $output = "";
348     }
349 gutsche 1.5 }
350    
351 gutsche 1.8 # take site specific or if not found default max site queue
352 gutsche 1.20 # read in from siteconfig file
353     my %sitelimits = ();
354 gutsche 1.21 my %siteNameTranslation = ();
355 gutsche 1.20 if ( $self->{SITECONFIG} ) {
356     open(siteconfig_file,"$self->{SITECONFIG}");
357     my @line_array = <siteconfig_file>;
358     for (my $i = 0; $i < scalar @line_array; ++$i) {
359     if (defined $line_array[$i] ) {
360     if ( $line_array[$i] !~ /^#/ && $line_array[$i] !~ /^\n/ ) {
361 asciaba 1.33 my ($tempsite, $tempshortsite, $templimit) = split(/\s+/,$line_array[$i]);
362 gutsche 1.20 chomp($tempsite);
363 gutsche 1.21 chomp($tempshortsite);
364 gutsche 1.20 chomp($templimit);
365 asciaba 1.37 $sitelimits{$tempshortsite} = $templimit;
366     $siteNameTranslation{$tempshortsite} = $tempshortsite;
367 gutsche 1.20 }
368     }
369     }
370     close siteconfig_file;
371     }
372 gutsche 1.21
373     # If the site isn't too busy already, ignore.
374 belforte 1.30 my $running = ($sitestats{$siteNameTranslation{$site}}{R} || 0);
375     my $scheduled = ($sitestats{$siteNameTranslation{$site}}{S} || 0);
376     my $created = ($sitestats{$siteNameTranslation{$site}}{C} || 0);
377     my $pending = $created + $scheduled + $running;
378 gutsche 1.20 my $max_queue = $sitelimits{$site} || $self->{MAX_SITE_QUEUE};
379 gutsche 1.26 if ( $pending > $max_queue ) {
380 belforte 1.30 &logmsg("$siteNameTranslation{$site} : Task not created. number of R+S+C jobs ($running + $scheduled + $created = $pending) exceeds site limit of $site ($max_queue)");
381 gutsche 1.4 next;
382     }
383    
384     # Find out what is already pending for this task. First find all
385     # existing tasks in the repository, the latest generation.
386     my $datestamp = strftime ("%y%m%d", gmtime(time()));
387 gutsche 1.21 my $taskdir = "$self->{TASKREPO}/$datestamp/$siteNameTranslation{$site}/$tier";
388    
389     # create short unique taskbase from $datestamp.$site.$dataset.$tier.$owner
390     my $taskbase = $self->createHashFromString ("$datestamp.$site.$dataset.$tier.$owner");
391     chomp($taskbase);
392    
393 gutsche 1.4 my @existing = sort { $a <=> $b } map { /.*\.(\d+)$/ } <$taskdir/$taskbase.*>;
394     my $curgen = pop(@existing) || 0;
395     my $nextgen = $curgen + 1;
396    
397     # OK to create the task if enough time has passed from previous
398     # task creation, or there is no previous task.
399     if (! -f "$taskdir/$taskbase.$curgen/crab.cfg"
400 gutsche 1.21 || (((stat("$taskdir/$taskbase.$curgen/crab.cfg"))[9]
401 asciaba 1.32 < time() - $secsinit)))
402 gutsche 1.4 {
403     my $mydir = $0; $mydir =~ s|/[^/]+$||;
404     my $drop = sprintf("%s.%03d", $taskbase, $nextgen);
405 gutsche 1.21 my $ret = &runcmd ("$mydir/CrabJobs",
406     "-cfg", "$mydir/$cfg",
407     "-datasetpath", $datasetpath,
408 gutsche 1.4 "-output", $output,
409 gutsche 1.21 "-totalevents", $totalevents,
410 asciaba 1.37 "-whitelistce", $site,
411     "-whitelistse", $sitese,
412 asciaba 1.32 "-cmssw", $cmssw,
413     "-eventsperjob", $events,
414 gutsche 1.4 "-scheduler", $self->{SCHEDULER},
415 gutsche 1.21 "-jobname", "$taskdir/$drop");
416 gutsche 1.4 die "$drop: failed to create task: @{[&runerror($ret)]}\n" if $ret;
417 gutsche 1.21
418 gutsche 1.4 &output ("$taskdir/$drop/TASK_INIT.txt",
419     &mytimeofday () . "\n");
420    
421     my $dropdir = "$self->{WORKDIR}/$drop";
422     mkdir "$dropdir" || die "$dropdir: cannot create: $!\n";
423 gutsche 1.21 if (&output ("$dropdir/task", "$taskdir/$drop")) {
424     &touch ("$dropdir/done");
425     $self->relayDrop ($drop);
426 gutsche 1.23 &logmsg("stats: $drop $datestamp $site $dataset $tier $owner @{[&formatElapsedTime($self->{STARTTIME})]} success");
427 gutsche 1.21 } else {
428 gutsche 1.23 &alert ("$drop $datestamp $site $dataset $tier $owner: failed to create drop");
429 gutsche 1.21 &rmtree ([ "$self->{WORKDIR}/$drop" ]);
430     }
431 gutsche 1.4 }
432     }