rbbt-util 5.30.12 → 5.31.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6d407fc5c2e576419062f2f72e52a4c67d8c740447b54eb7838ecaf769ee1c33
4
- data.tar.gz: a9f11e1db995f7ea7179964316b6c7347e01fcd7323b6237e8762320455ca8ce
3
+ metadata.gz: d850d97bff4cc0cd4123cbfdd2301c8d777fda47e6767542b6e3d9dc8ed22501
4
+ data.tar.gz: df69bfc3ca3b2605dd0171dd553ddf0f6dd0c064bf1fe66c5c9e8909d23760d8
5
5
  SHA512:
6
- metadata.gz: 46718e67f59ab2b9ae5e3fd1d6fb0e7deffe5b1f5daf95669d7cc11022c846e829640cee45033aaced7409c291eacc29bd04253ff5f978e98e4860d777046188
7
- data.tar.gz: b214c317054c28c81d742a0eb5af3c3a1bddcc3fb48223ba7d2ea7f3ab95e155e642d4100d5353bc04cbfc77bfcdd215df57c37be0a3fc0de0fb6757e5c3a269
6
+ metadata.gz: 2ae6c6d6d098043d8117eadfcfb47dbc97d2dcc7af2ffa96775d8ba54fc2ec0b063311db6a3ba8c48f6c0d11d066ab2182676b6c87a4aa3075bd695ff4ca57cb
7
+ data.tar.gz: 3de13554f1066d6fa7ee8be74842dcc4b4bbadbe422ca943c7ca272fe735643673067841cff077c9ea1c9eb39d5d1641dd91e3926a4b276fa80815baf17cf31a
data/lib/rbbt/hpc.rb CHANGED
@@ -1,3 +1,6 @@
1
1
  require 'rbbt-util'
2
2
  require 'rbbt/util/cmd'
3
+ require 'rbbt/hpc/batch'
4
+ require 'rbbt/hpc/orchestrate'
3
5
  require 'rbbt/hpc/slurm'
6
+ require 'rbbt/hpc/lsf'
@@ -0,0 +1,621 @@
1
+ module HPC
2
+ class SBATCH < Exception;
3
+ attr_accessor :directory
4
+ def initialize(directory)
5
+ @directory = directory
6
+ end
7
+ end
8
+
9
+ module TemplateGeneration
10
+ def exec_cmd(job, options = {})
11
+ env_cmd = Misc.process_options options, :env_cmd
12
+ development = Misc.process_options options, :development
13
+
14
+ if options[:singularity]
15
+
16
+ group, user, user_group, scratch_group_dir, projects_group_dir = options.values_at :group, :user, :user_group, :scratch_group_dir, :projects_group_dir
17
+
18
+ singularity_img, singularity_opt_dir, singularity_ruby_inline = options.values_at :singularity_img, :singularity_opt_dir, :singularity_ruby_inline
19
+
20
+ singularity_cmd = %(singularity exec -e -B #{singularity_opt_dir}:/singularity_opt/ -B /apps/)
21
+
22
+ if contain = options[:contain]
23
+ contain = File.expand_path(contain)
24
+ singularity_cmd << %( -C -H "#{contain}" \
25
+ -B "#{options[:batch_dir]}" \
26
+ -B /scratch/tmp \
27
+ #{ group != user_group ? "-B /gpfs/projects/#{user_group}" : "" } \
28
+ -B #{scratch_group_dir} \
29
+ -B #{projects_group_dir} \
30
+ -B "#{singularity_ruby_inline}":"#{contain}/.ruby_inline":rw \
31
+ -B ~/git:"#{contain}/git":ro \
32
+ #{Open.exists?('~/.rbbt/software/opt/')? '-B ~/.rbbt/software/opt/:"/opt/":ro' : '' } \
33
+ -B ~/.rbbt:"#{contain}/home/":ro)
34
+ singularity_cmd << " #{singularity_img} "
35
+ end
36
+ env_cmd ||= ""
37
+ env_cmd << " TMPDIR='#{contain}/.rbbt/tmp' "
38
+ end
39
+
40
+ if env_cmd
41
+ exec_cmd = %(env #{env_cmd} rbbt)
42
+ else
43
+ exec_cmd = %(rbbt)
44
+ end
45
+
46
+ exec_cmd << "--dev '#{development}'" if development
47
+
48
+ exec_cmd = singularity_cmd + exec_cmd if singularity_cmd
49
+
50
+ exec_cmd
51
+ end
52
+
53
+ def rbbt_job_exec_cmd(job, options)
54
+
55
+ jobname = job.clean_name
56
+ workflow = job.workflow
57
+ task = job.task_name
58
+
59
+ Misc.add_defaults options, :jobname => jobname
60
+
61
+ task = Symbol === job.overriden ? job.overriden : job.task_name
62
+
63
+ if job.overriden
64
+ override_deps = job.rec_dependencies.
65
+ select{|dep| Symbol === dep.overriden }.
66
+ collect do |dep|
67
+
68
+ name = [dep.workflow.to_s, dep.task_name] * "#"
69
+ [name, dep.path] * "="
70
+ end * ","
71
+
72
+ options[:override_deps] = override_deps
73
+ end
74
+
75
+ # Save inputs into inputs_dir
76
+ inputs_dir = Misc.process_options options, :inputs_dir
77
+ saved = Step.save_job_inputs(job, inputs_dir) if inputs_dir
78
+ options[:load_inputs] = inputs_dir if saved && saved.any?
79
+
80
+ saved.each do |input|
81
+ options.delete input
82
+ end if saved
83
+
84
+ cmds = CMD.process_cmd_options options.merge(:add_option_dashes => true)
85
+
86
+ <<-EOF.strip
87
+ workflow task #{workflow} #{task} #{cmds}
88
+ EOF
89
+ end
90
+
91
+ def header(options)
92
+ header =<<-EOF
93
+ #!/bin/bash
94
+ EOF
95
+
96
+ header
97
+ end
98
+
99
+ def batch_options(job, options)
100
+ IndiferentHash.setup(options)
101
+
102
+ batch_options = IndiferentHash.setup({})
103
+
104
+ keys = [
105
+ :batch_dir,
106
+ :batch_modules,
107
+ :batch_name,
108
+ :contain,
109
+ :contain_and_sync,
110
+ :copy_image,
111
+ :drbbt,
112
+ :env_cmd,
113
+ :exclusive,
114
+ :highmem,
115
+ :manifest,
116
+ :nodes,
117
+ :queue,
118
+ :singularity,
119
+ :sync,
120
+ :task_cpus,
121
+ :time,
122
+ :user_group,
123
+ :wipe_container,
124
+ :workdir,
125
+ ]
126
+
127
+ keys.each do |key|
128
+ next if options[key].nil?
129
+ batch_options[key] = Misc.process_options options, key
130
+ end
131
+
132
+ batch_dir = batch_options[:batch_dir]
133
+
134
+ batch_name = File.basename(batch_dir)
135
+ inputs_dir = File.join(batch_dir, 'inputs_dir')
136
+
137
+ keys_from_config = [
138
+ :queue,
139
+ :highmem,
140
+ :exclusive,
141
+ :env_cmd,
142
+ :user_group,
143
+ :singularity_img,
144
+ :singularity_opt_dir,
145
+ :singularity_ruby_inline,
146
+ :singularity
147
+ ]
148
+
149
+ keys_from_config.each do |key|
150
+ next unless batch_options.include? key
151
+ default_value = Rbbt::Config.get(key, "batch_#{key}", "batch")
152
+ next if default_value.nil?
153
+ Misc.add_defaults batch_options, default_value
154
+ end
155
+
156
+ user = batch_options[:user] ||= ENV['USER'] || `whoami`.strip
157
+ group = batch_options[:group] ||= File.basename(File.dirname(ENV['HOME']))
158
+ batch_options[:scratch_group_dir] = File.join('/gpfs/scratch/', group)
159
+ batch_options[:projects_group_dir] = File.join('/gpfs/projects/', group)
160
+
161
+ if batch_options[:contain_and_sync]
162
+ if batch_options[:contain].nil?
163
+ contain_base = Rbbt::Config.get(:contain_base_dir, :batch_contain, :batch, :default => "/scratch/tmp/rbbt-[USER]")
164
+ contain_base = contain_base.sub('[USER]', user)
165
+ random_file = TmpFile.random_name
166
+ batch_options[:contain] = File.join(contain_base, random_file)
167
+ end
168
+
169
+ batch_options[:sync] ||= "~/.rbbt/var/jobs"
170
+ batch_options[:wipe_container] ||= 'post'
171
+ end
172
+
173
+ if batch_options[:contain] && ! batch_options[:singularity]
174
+ options[:workdir_all] = batch_options[:contain]
175
+ end
176
+
177
+ Misc.add_defaults batch_options,
178
+ :batch_name => batch_name,
179
+ :inputs_dir => inputs_dir,
180
+ :queue => 'debug',
181
+ :nodes => 1,
182
+ :step_path => job.path,
183
+ :task_cpus => 1,
184
+ :time => '2min',
185
+ :env_cmd => '_JAVA_OPTIONS="-Xms1g -Xmx${MAX_MEMORY}m"',
186
+ :singularity_img => ENV["SINGULARITY_IMG"] || "~/rbbt.singularity.img",
187
+ :singularity_ruby_inline => ENV["SINGULARITY_RUBY_INLINE"] || "~/.singularity_ruby_inline",
188
+ :singularity_opt_dir => ENV["SINGULARITY_OPT_DIR"] || "~/singularity_opt",
189
+ :workdir => Dir.pwd
190
+
191
+ exec_cmd = exec_cmd(job, batch_options)
192
+ rbbt_cmd = rbbt_job_exec_cmd(job, options)
193
+
194
+ Misc.add_defaults batch_options,
195
+ :exec_cmd => exec_cmd,
196
+ :rbbt_cmd => rbbt_cmd
197
+
198
+ batch_dir = batch_options[:batch_dir]
199
+
200
+ Misc.add_defaults batch_options,
201
+ :fout => File.join(batch_dir, 'std.out'),
202
+ :ferr => File.join(batch_dir, 'std.err'),
203
+ :fjob => File.join(batch_dir, 'job.id'),
204
+ :fdep => File.join(batch_dir, 'dependencies.list'),
205
+ :fcfdep => File.join(batch_dir, 'canfail_dependencies.list'),
206
+ :fexit => File.join(batch_dir, 'exit.status'),
207
+ :fsync => File.join(batch_dir, 'sync.log'),
208
+ :fsexit => File.join(batch_dir, 'sync.status'),
209
+ :fcmd => File.join(batch_dir, 'command.batch')
210
+
211
+ batch_options
212
+ end
213
+
214
+ def meta_data(options)
215
+ meta =<<-EOF
216
+ #MANIFEST: #{(options[:manifest] || []) * ", "}
217
+ #DEPENDENCIES: #{(options[:dependencies] || []) * ", "}
218
+ #EXEC_CMD: #{options[:exec_cmd]}
219
+ #CMD: #{options[:rbbt_cmd]}
220
+ #STEP_PATH: #{options[:step_path]}
221
+ EOF
222
+
223
+ meta = meta.split("\n").reject{|line| line =~ /: $/} * "\n"
224
+ meta
225
+ end
226
+
227
+ def load_modules(modules = [])
228
+ modules = modules.split(/,\s*/) if String === modules
229
+
230
+ str = ""
231
+ modules.each do |mod|
232
+ str << "module load #{ mod }" << "\n"
233
+ end if modules
234
+
235
+ str
236
+ end
237
+
238
+ def batch_system_variables
239
+ <<-EOF
240
+ let MAX_MEMORY="$(grep MemTotal /proc/meminfo|grep -o "[[:digit:]]*") / 1024"
241
+ EOF
242
+ end
243
+
244
+ def prepare_environment(options = {})
245
+ modules = options[:batch_modules]
246
+
247
+ prepare_environment = ""
248
+
249
+ functions = ""
250
+
251
+ if contain = options[:contain]
252
+ contain = File.expand_path(contain)
253
+ functions +=<<-EOF
254
+ function batch_erase_contain_dir(){
255
+ rm -Rfv '#{contain}' 2>1 >> '#{options[:fsync]}'
256
+ }
257
+ EOF
258
+
259
+ prepare_environment +=<<-EOF
260
+ if ls -A '#{contain}' &> /dev/null ; then
261
+ empty_contain_dir="false"
262
+ else
263
+ empty_contain_dir="true"
264
+ fi
265
+ EOF
266
+
267
+ prepare_environment +=<<-EOF if options[:wipe_container] == 'force'
268
+ batch_erase_contain_dir()
269
+ EOF
270
+ end
271
+
272
+ if sync = options[:sync]
273
+ source = if options[:singularity]
274
+ File.join(options[:contain], '.rbbt/var/jobs')
275
+ elsif options[:contain]
276
+ File.join(options[:contain], 'var/jobs')
277
+ else
278
+ '~/.rbbt/var/jobs/'
279
+ end
280
+
281
+ source = File.expand_path(source)
282
+ sync = File.expand_path(sync)
283
+ functions +=<<-EOF
284
+ function batch_sync_contain_dir(){
285
+ mkdir -p "$(dirname '#{sync}')"
286
+ rsync -avztAXHP --copy-unsafe-links "#{source}/" "#{sync}/" 2>1 >> '#{options[:fsync]}'
287
+ sync_es="$?"
288
+ echo $sync_es > '#{options[:fsexit]}'
289
+ find '#{sync}' -type l -ls | awk '$13 ~ /^#{sync.gsub('/','\/')}/ { sub("#{source}", "#{sync}", $13); print $11, $13 }' | while read A B; do rm $A; ln -s $B $A; done
290
+ }
291
+ EOF
292
+ end
293
+
294
+ if options[:singularity]
295
+
296
+ group, user, user_group, scratch_group_dir, projects_group_dir = options.values_at :group, :user, :user_group, :scratch_group_dir, :projects_group_dir
297
+
298
+ singularity_img, singularity_opt_dir, singularity_ruby_inline = options.values_at :singularity_img, :singularity_opt_dir, :singularity_ruby_inline
299
+
300
+ prepare_environment +=<<-EOF
301
+ # Load singularity modules
302
+ module load intel/2018.1
303
+ module load singularity
304
+ mkdir -p "#{singularity_opt_dir}"
305
+ EOF
306
+
307
+ if contain
308
+
309
+ prepare_environment +=<<-EOF
310
+ # Prepare container for singularity
311
+ mkdir -p "#{contain}/.rbbt/etc/"
312
+
313
+ for dir in .ruby_inline git home; do
314
+ mkdir -p "#{contain}/$dir"
315
+ done
316
+
317
+ for tmpd in persist_locks produce_locks R_sockets sensiblewrite sensiblewrite_locks step_info_locks tsv_open_locks; do
318
+ mkdir -p "#{contain}/.rbbt/tmp/$tmpd"
319
+ done
320
+
321
+ # Copy environment
322
+ cp ~/.rbbt/etc/environment #{contain}/.rbbt/etc/
323
+
324
+ # Set search_paths
325
+ echo "singularity: /singularity_opt/{PKGDIR}/{TOPLEVEL}/{SUBPATH}" > #{contain}/.rbbt/etc/search_paths
326
+ echo "rbbt_user: /home/rbbt/.rbbt/{TOPLEVEL}/{SUBPATH}" >> #{contain}/.rbbt/etc/search_paths
327
+ echo "outside_home: #{contain}/home/{TOPLEVEL}/{SUBPATH}" >> #{contain}/.rbbt/etc/search_paths
328
+ echo "group_projects: #{projects_group_dir}/{PKGDIR}/{TOPLEVEL}/{SUBPATH}" >> #{contain}/.rbbt/etc/search_paths
329
+ echo "group_scratch: #{scratch_group_dir}/{PKGDIR}/{TOPLEVEL}/{SUBPATH}" >> #{contain}/.rbbt/etc/search_paths
330
+ echo "user_projects: #{projects_group_dir}/#{user}/{PKGDIR}/{TOPLEVEL}/{SUBPATH}" >> #{contain}/.rbbt/etc/search_paths
331
+ echo "user_scratch: #{scratch_group_dir}/#{user}/{PKGDIR}/{TOPLEVEL}/{SUBPATH}" >> #{contain}/.rbbt/etc/search_paths
332
+ EOF
333
+ end
334
+ end
335
+
336
+ batch_system_variables + load_modules(modules) + "\n" + functions + "\n" + prepare_environment
337
+ end
338
+
339
+ def execute(options)
340
+ exec_cmd, job_cmd = options.values_at :exec_cmd, :rbbt_cmd
341
+
342
+ <<-EOF
343
+ step_path=$(
344
+ #{exec_cmd} #{job_cmd} --printpath
345
+ )
346
+ exit_status=$?
347
+
348
+ [[ -z $BATCH_JOB_ID ]] || #{exec_cmd} workflow write_info --recursive --force=false --check_pid "$step_path" batch_job $BATCH_JOB_ID
349
+ [[ -z $BATCH_SYSTEM ]] || #{exec_cmd} workflow write_info --recursive --force=false --check_pid "$step_path" batch_system $BATCH_SYSTEM
350
+ EOF
351
+ end
352
+
353
+ def sync_environment(options = {})
354
+ sync_environment = ""
355
+
356
+ if options[:sync]
357
+ sync_environment +=<<-EOF
358
+ if [ $exit_status == '0' ]; then
359
+ batch_sync_contain_dir
360
+ else
361
+ sync_es=$exit_status
362
+ fi
363
+ EOF
364
+ end
365
+
366
+ sync_environment
367
+ end
368
+
369
+ def cleanup_environment(options = {})
370
+ cleanup_environment = ""
371
+ if options[:sync]
372
+ if options[:wipe_container] == 'force'
373
+ cleanup_environment +=<<-EOF
374
+ batch_erase_contain_dir
375
+ EOF
376
+ elsif options[:wipe_container] == 'post' || options[:wipe_container] == 'both'
377
+ cleanup_environment +=<<-EOF
378
+ if [ $sync_es == '0' -a $empty_contain_dir == 'true' ]; then
379
+ batch_erase_contain_dir
380
+ fi
381
+ EOF
382
+ end
383
+ end
384
+ cleanup_environment
385
+ end
386
+
387
+ def coda(options)
388
+ coda =<<-EOF
389
+ echo $exit_status > '#{options[:fexit]}'
390
+ EOF
391
+
392
+ if options[:sync]
393
+ coda +=<<-EOF
394
+ if [ $sync_es == '0' ]; then
395
+ exit $exit_status
396
+ else
397
+ exit $sync_es
398
+ fi
399
+ EOF
400
+ else
401
+ coda +=<<-EOF
402
+ exit $exit_status
403
+ EOF
404
+ end
405
+
406
+ coda
407
+ end
408
+
409
+ def job_template(job, options = {})
410
+ batch_options = batch_options job, options
411
+
412
+ header = self.header(batch_options)
413
+
414
+ meta_data = self.meta_data(batch_options)
415
+
416
+ prepare_environment = self.prepare_environment(batch_options)
417
+
418
+ execute = self.execute(batch_options)
419
+
420
+ sync_environment = self.sync_environment(batch_options)
421
+
422
+ cleanup_environment = self.cleanup_environment(batch_options)
423
+
424
+ coda = self.coda(batch_options)
425
+
426
+ <<-EOF
427
+ #{header}
428
+
429
+ # #{Log.color :green, "0. Meta-data"}
430
+ #{meta_data}
431
+
432
+ # #{Log.color :green, "1. Prepare environment"}
433
+ #{prepare_environment}
434
+
435
+ # #{Log.color :green, "2. Execute"}
436
+ #{execute}
437
+
438
+ # #{Log.color :green, "3. Sync and cleanup environment"}
439
+ #{sync_environment}
440
+ #{cleanup_environment}
441
+
442
+ # #{Log.color :green, "4. Exit"}
443
+ #{coda}
444
+ EOF
445
+ end
446
+
447
+ def prepare_submision(template, batch_dir, clean_batch_job = false, batch_dependencies = [])
448
+ Open.mkdir batch_dir
449
+ fcmd = File.join(batch_dir, 'command.batch')
450
+ fdep = File.join(batch_dir, 'dependencies.list')
451
+ fcfdep = File.join(batch_dir, 'canfail_dependencies.list')
452
+
453
+ Open.write(fcmd, template)
454
+
455
+ %w(std.out std.err job.id job.status dependencies.list canfail_dependencies.list exit.status sync.log inputs_dir).each do |filename|
456
+ path = File.join(batch_dir, filename)
457
+ Open.rm_rf path if File.exists? path
458
+ end if clean_batch_job
459
+
460
+ batch_dependencies = [] if batch_dependencies.nil?
461
+
462
+ canfail_dependencies = batch_dependencies.select{|dep| dep =~ /^canfail:(\d+)/ }.collect{|dep| dep.partition(":").last}
463
+ dependencies = batch_dependencies.reject{|dep| dep =~ /^canfail:(\d+)/ }
464
+
465
+ Open.write(fdep, dependencies * "\n") if dependencies.any?
466
+ Open.write(fcfdep, canfail_dependencies * "\n") if canfail_dependencies.any?
467
+
468
+ fcmd
469
+ end
470
+
471
+
472
+ def run_job(job, options = {})
473
+ system = self.to_s.split("::").last
474
+
475
+ batch_base_dir, clean_batch_job, remove_batch_dir, procpath, tail, batch_dependencies, dry_run = Misc.process_options options,
476
+ :batch_base_dir, :clean_batch_job, :remove_batch_dir, :batch_procpath, :tail, :batch_dependencies, :dry_run,
477
+ :batch_base_dir => File.expand_path(File.join('~/rbbt-batch'))
478
+
479
+ workflow = job.workflow
480
+ task_name = job.task_name
481
+
482
+ TmpFile.with_file(nil, remove_batch_dir, :tmpdir => batch_base_dir, :prefix => "#{system}_rbbt_job-#{workflow.to_s}-#{task_name}-") do |batch_dir|
483
+ Misc.add_defaults options,
484
+ :batch_dir => batch_dir,
485
+ :inputs_dir => File.join(batch_dir, "inputs_dir")
486
+
487
+ options[:procpath_performance] ||= File.join(batch_dir, "procpath##{procpath.gsub(',', '#')}") if procpath
488
+
489
+ template = self.job_template(job, options.dup)
490
+
491
+ fcmd = prepare_submision(template, options[:batch_dir], clean_batch_job, batch_dependencies)
492
+
493
+ batch_job = run_template(batch_dir, dry_run)
494
+
495
+ return batch_job unless tail
496
+
497
+ t_monitor = Thread.new do
498
+ self.follow_job(batch_dir, :STDERR)
499
+ end
500
+ self.wait_for_job(batch_dir)
501
+ t_monitor.raise Aborted
502
+ return unless Open.read(File.join(batch_dir, 'exit.status')).strip == '0'
503
+ path = Open.read(File.join(batch_dir, 'std.out')).strip
504
+ if Open.exists?(path) && job.path != path
505
+ Log.info "Path of BATCH job #{path} is different from original job #{job.path}. Stablishing link."
506
+ Open.ln path, job.path
507
+ Open.ln path + '.info', job.path + '.info' if Open.exists?(path + '.info')
508
+ Open.ln path + '.files', job.path + '.files' if Open.exists?(path + '.files')
509
+ end
510
+ batch_job
511
+
512
+ end
513
+ end
514
+
515
+ def follow_job(batch_dir, tail = true)
516
+ fjob = File.join(batch_dir, 'job.id')
517
+ fout = File.join(batch_dir, 'std.out')
518
+ ferr = File.join(batch_dir, 'std.err')
519
+ fexit = File.join(batch_dir, 'exit.status')
520
+ fstatus = File.join(batch_dir, 'job.status')
521
+
522
+ job = Open.read(fjob).strip if Open.exists?(fjob)
523
+
524
+ if job && ! File.exists?(fexit)
525
+ begin
526
+ status_txt = job_status(job)
527
+ STDERR.puts Log.color(:magenta, "Status [#{job.to_i}]:")
528
+ STDERR.puts status_txt
529
+ lines = status_txt.split("\n").length
530
+ rescue
531
+ if ! File.exists?(fexit)
532
+ STDERR.puts Log.color(:magenta, "Job #{job.to_i} not done and not running. STDERR:")
533
+ STDERR.puts Open.read(ferr)
534
+ end
535
+ return
536
+ end
537
+ end
538
+
539
+ if File.exists?(fexit)
540
+ exit_status = Open.read(fexit)
541
+ if exit_status.to_i == 0
542
+ STDERR.puts Log.color(:magenta, "Job #{job} done with exit_status 0. STDOUT:")
543
+ STDERR.puts Open.read(fout)
544
+ else
545
+ STDERR.puts Log.color(:magenta, "Job #{job.to_i} done with exit_status #{exit_status}. STDERR:")
546
+ STDERR.puts Open.read(ferr)
547
+ end
548
+ return
549
+ end
550
+
551
+ if tail
552
+ Log.severity = 10
553
+ while ! File.exists? fout
554
+ if job
555
+ STDERR.puts
556
+ Log.clear_line(STDERR)
557
+ STDERR.write Log.color(:magenta, "Waiting for Output")
558
+ 3.times do
559
+ STDERR.write Log.color(:magenta, ".")
560
+ sleep 1
561
+ end
562
+ status_txt = job_status(job)
563
+ lines.times do
564
+ Log.clear_line(STDERR)
565
+ end
566
+ Log.clear_line(STDERR)
567
+ STDERR.puts Log.color(:magenta, "Status [#{job.to_i}]:")
568
+ STDERR.puts status_txt
569
+ lines = status_txt.split("\n").length
570
+ end
571
+ end
572
+ STDERR.puts
573
+ Log.clear_line(STDERR)
574
+ STDERR.puts Log.color(:magenta, "Output:")
575
+ begin
576
+ status_txt = job_status(job)
577
+ Open.write(fstatus, status_txt) unless status_txt.nil? || status_txt.empty?
578
+ out = CMD.cmd("tail -f '#{fout}'", :pipe => true) if File.exists?(fout) and not tail == :STDERR
579
+ err = CMD.cmd("tail -f '#{ferr}'", :pipe => true) if File.exists?(ferr)
580
+
581
+ terr = Misc.consume_stream(err, true, STDERR) if err
582
+ tout = Misc.consume_stream(out, true, STDOUT) if out
583
+
584
+ sleep 3 while job_status(job).include? job.to_s
585
+ rescue Aborted
586
+ ensure
587
+ begin
588
+ terr.exit if terr
589
+ tout.exit if tout
590
+ err.close if err
591
+ err.join if err
592
+ rescue Exception
593
+ end
594
+
595
+ begin
596
+ out.close if out
597
+ out.join if out
598
+ rescue Exception
599
+ end
600
+ end
601
+ end
602
+ end
603
+
604
+ def wait_for_job(batch_dir, time = 1)
605
+ fexit = File.join(batch_dir, 'exit.status')
606
+ fjob = File.join(batch_dir, 'job.id')
607
+ job = Open.read(fjob) if Open.exists?(fjob)
608
+
609
+ while ! Open.exists?(fexit)
610
+ sleep time
611
+ end
612
+ end
613
+
614
+ end
615
+
616
+ module BATCH
617
+ extend HPC::TemplateGeneration
618
+ end
619
+
620
+ end
621
+