ood_core 0.10.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.travis.yml +2 -2
- data/CHANGELOG.md +54 -1
- data/README.md +6 -5
- data/lib/ood_core.rb +1 -0
- data/lib/ood_core/batch_connect/template.rb +44 -2
- data/lib/ood_core/cluster.rb +15 -0
- data/lib/ood_core/clusters.rb +19 -5
- data/lib/ood_core/invalid_cluster.rb +37 -0
- data/lib/ood_core/job/adapter.rb +35 -4
- data/lib/ood_core/job/adapters/drmaa.rb +1 -1
- data/lib/ood_core/job/adapters/helper.rb +20 -1
- data/lib/ood_core/job/adapters/linux_host.rb +5 -1
- data/lib/ood_core/job/adapters/linux_host/launcher.rb +22 -9
- data/lib/ood_core/job/adapters/linux_host/templates/script_wrapper.erb.sh +15 -1
- data/lib/ood_core/job/adapters/lsf.rb +5 -0
- data/lib/ood_core/job/adapters/lsf/batch.rb +5 -3
- data/lib/ood_core/job/adapters/lsf/helper.rb +29 -23
- data/lib/ood_core/job/adapters/pbspro.rb +58 -33
- data/lib/ood_core/job/adapters/sge.rb +4 -0
- data/lib/ood_core/job/adapters/sge/batch.rb +7 -7
- data/lib/ood_core/job/adapters/sge/helper.rb +19 -18
- data/lib/ood_core/job/adapters/sge/qstat_xml_j_r_listener.rb +54 -8
- data/lib/ood_core/job/adapters/sge/qstat_xml_r_listener.rb +25 -2
- data/lib/ood_core/job/adapters/slurm.rb +85 -38
- data/lib/ood_core/job/adapters/torque.rb +34 -22
- data/lib/ood_core/job/adapters/torque/batch.rb +29 -12
- data/lib/ood_core/job/array_ids.rb +18 -53
- data/lib/ood_core/job/script.rb +19 -2
- data/lib/ood_core/version.rb +1 -1
- data/ood_core.gemspec +2 -1
- metadata +20 -6
@@ -1,5 +1,19 @@
|
|
1
1
|
#!/bin/bash
|
2
|
-
|
2
|
+
SSH_HOSTS=(<%= ssh_hosts.join(' ').to_s %>)
|
3
|
+
hostnames=`hostname -A`
|
4
|
+
for host in ${SSH_HOSTS[@]}
|
5
|
+
do
|
6
|
+
if [[ " ${hostnames[@]} " =~ " ${host} " ]]; then
|
7
|
+
hostname=$host
|
8
|
+
fi
|
9
|
+
done
|
10
|
+
|
11
|
+
if [ -z "$hostname" ]; then
|
12
|
+
printf >&2 "ERROR: Can't start job on [${hostnames[@]}] because it does not match any hostname configured \nin ssh_hosts [${SSH_HOSTS[@]}]. The output of 'hostname -A' must match an entry in ssh_hosts \nfrom the cluster configuration."
|
13
|
+
exit 1
|
14
|
+
fi
|
15
|
+
|
16
|
+
echo $hostname
|
3
17
|
|
4
18
|
# Put the script into a temp file on localhost
|
5
19
|
<% if debug %>
|
@@ -14,6 +14,7 @@ module OodCore
|
|
14
14
|
# @option config [#to_s] :serverdir ('') Path to lsf client etc dir
|
15
15
|
# @option config [#to_s] :cluster ('') name of cluster, if in multi-cluster mode
|
16
16
|
# @option config [#to_h] :bin_overrides ({}) Optional overrides to LSF client executables
|
17
|
+
# @option config [#to_s] :submit_host ('') Host to submit commands to
|
17
18
|
def self.build_lsf(config)
|
18
19
|
batch = Adapters::Lsf::Batch.new(config.to_h.symbolize_keys)
|
19
20
|
Adapters::Lsf.new(batch: batch)
|
@@ -167,6 +168,10 @@ module OodCore
|
|
167
168
|
raise JobAdapterError, e.message
|
168
169
|
end
|
169
170
|
|
171
|
+
def directive_prefix
|
172
|
+
'#BSUB'
|
173
|
+
end
|
174
|
+
|
170
175
|
private
|
171
176
|
# Determine state from LSF state code
|
172
177
|
def get_state(st)
|
@@ -2,21 +2,22 @@
|
|
2
2
|
#
|
3
3
|
# @api private
|
4
4
|
class OodCore::Job::Adapters::Lsf::Batch
|
5
|
-
attr_reader :bindir, :libdir, :envdir, :serverdir, :cluster, :bin_overrides
|
5
|
+
attr_reader :bindir, :libdir, :envdir, :serverdir, :cluster, :bin_overrides, :submit_host, :strict_host_checking
|
6
6
|
|
7
7
|
# The root exception class that all LSF-specific exceptions inherit
|
8
8
|
# from
|
9
9
|
class Error < StandardError; end
|
10
10
|
|
11
11
|
# @param bin [#to_s] path to LSF installation binaries
|
12
|
-
def initialize(bindir: "", envdir: "", libdir: "", serverdir: "", cluster: "", bin_overrides: {}, **_)
|
12
|
+
def initialize(bindir: "", envdir: "", libdir: "", serverdir: "", cluster: "", bin_overrides: {}, submit_host: "", strict_host_checking: true, **_)
|
13
13
|
@bindir = Pathname.new(bindir.to_s)
|
14
|
-
|
15
14
|
@envdir = Pathname.new(envdir.to_s)
|
16
15
|
@libdir = Pathname.new(libdir.to_s)
|
17
16
|
@serverdir = Pathname.new(serverdir.to_s)
|
18
17
|
@cluster = cluster.to_s
|
19
18
|
@bin_overrides = bin_overrides
|
19
|
+
@submit_host = submit_host.to_s
|
20
|
+
@strict_host_checking = strict_host_checking
|
20
21
|
end
|
21
22
|
|
22
23
|
def default_env
|
@@ -143,6 +144,7 @@ class OodCore::Job::Adapters::Lsf::Batch
|
|
143
144
|
cmd = OodCore::Job::Adapters::Helper.bin_path(cmd, bindir, bin_overrides)
|
144
145
|
args = cluster_args + args
|
145
146
|
env = default_env.merge(env.to_h)
|
147
|
+
cmd, args = OodCore::Job::Adapters::Helper.ssh_wrap(submit_host, cmd, args, strict_host_checking, env)
|
146
148
|
o, e, s = Open3.capture3(env, cmd, *(args.map(&:to_s)), stdin_data: stdin.to_s)
|
147
149
|
s.success? ? o : raise(Error, e)
|
148
150
|
end
|
@@ -78,34 +78,40 @@ class OodCore::Job::Adapters::Lsf::Helper
|
|
78
78
|
def batch_submit_args(script, after: [], afterok: [], afternotok: [], afterany: [])
|
79
79
|
args = []
|
80
80
|
|
81
|
-
args
|
82
|
-
args
|
83
|
-
args
|
84
|
-
args[-1]
|
85
|
-
|
86
|
-
args
|
87
|
-
args
|
88
|
-
args
|
89
|
-
args
|
90
|
-
args
|
91
|
-
args
|
92
|
-
args
|
93
|
-
args
|
81
|
+
args.concat ["-P", script.accounting_id] unless script.accounting_id.nil?
|
82
|
+
args.concat ["-cwd", script.workdir.to_s] unless script.workdir.nil?
|
83
|
+
args.concat ["-J", script.job_name] unless script.job_name.nil?
|
84
|
+
args[-1].concat "[#{script.job_array_request}]" unless script.job_array_request.nil?
|
85
|
+
|
86
|
+
args.concat ["-q", script.queue_name] unless script.queue_name.nil?
|
87
|
+
args.concat ["-U", script.reservation_id] unless script.reservation_id.nil?
|
88
|
+
args.concat ["-sp", script.priority] unless script.priority.nil?
|
89
|
+
args.concat ["-H"] if script.submit_as_hold
|
90
|
+
args.concat (script.rerunnable ? ["-r"] : ["-rn"]) unless script.rerunnable.nil?
|
91
|
+
args.concat ["-b", script.start_time.localtime.strftime("%Y:%m:%d:%H:%M")] unless script.start_time.nil?
|
92
|
+
args.concat ["-W", (script.wall_time / 60).to_i] unless script.wall_time.nil?
|
93
|
+
args.concat ["-L", script.shell_path.to_s] unless script.shell_path.nil?
|
94
|
+
|
95
|
+
# environment
|
96
|
+
env = script.job_environment || {}
|
97
|
+
# To preserve pre-existing behavior we only act when true or false, when nil we do nothing
|
98
|
+
if script.copy_environment?
|
99
|
+
args.concat ["-env", (["all"] + env.keys).join(",")]
|
100
|
+
elsif script.copy_environment? == false
|
101
|
+
args.concat ["-env", (["none"] + env.keys).join(",")]
|
102
|
+
end
|
94
103
|
|
95
104
|
# input and output files
|
96
|
-
args
|
97
|
-
args
|
98
|
-
args
|
105
|
+
args.concat ["-i", script.input_path] unless script.input_path.nil?
|
106
|
+
args.concat ["-o", script.output_path] unless script.output_path.nil?
|
107
|
+
args.concat ["-e", script.error_path] unless script.error_path.nil?
|
99
108
|
|
100
109
|
# email
|
101
|
-
args
|
102
|
-
args
|
103
|
-
args
|
110
|
+
args.concat ["-B"] if script.email_on_started
|
111
|
+
args.concat ["-N"] if script.email_on_terminated
|
112
|
+
args.concat ["-u", script.email.join(",")] unless script.email.nil? || script.email.empty?
|
104
113
|
|
105
|
-
args
|
106
|
-
|
107
|
-
# environment
|
108
|
-
env = script.job_environment || {}
|
114
|
+
args.concat script.native unless script.native.nil?
|
109
115
|
|
110
116
|
{args: args, env: env}
|
111
117
|
end
|
@@ -10,17 +10,21 @@ module OodCore
|
|
10
10
|
# Build the PBS Pro adapter from a configuration
|
11
11
|
# @param config [#to_h] the configuration for job adapter
|
12
12
|
# @option config [Object] :host (nil) The batch server host
|
13
|
+
# @option config [Object] :submit_host ("") The login node where the job is submitted
|
14
|
+
# @option config [Object] :strict_host_checking (true) Whether to use strict host checking when ssh to submit_host
|
13
15
|
# @option config [Object] :exec (nil) Path to PBS Pro executables
|
14
16
|
# @option config [Object] :qstat_factor (nil) Deciding factor on how to
|
15
17
|
# call qstat for a user
|
16
18
|
# @option config [#to_h] :bin_overrides ({}) Optional overrides to PBS Pro client executables
|
17
19
|
def self.build_pbspro(config)
|
18
20
|
c = config.to_h.compact.symbolize_keys
|
19
|
-
host
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
host = c.fetch(:host, nil)
|
22
|
+
submit_host = c.fetch(:submit_host, "")
|
23
|
+
strict_host_checking = c.fetch(:strict_host_checking, true)
|
24
|
+
pbs_exec = c.fetch(:exec, nil)
|
25
|
+
qstat_factor = c.fetch(:qstat_factor, nil)
|
26
|
+
bin_overrides = c.fetch(:bin_overrides, {})
|
27
|
+
pbspro = Adapters::PBSPro::Batch.new(host: host, submit_host: submit_host, strict_host_checking: strict_host_checking, pbs_exec: pbs_exec, bin_overrides: bin_overrides)
|
24
28
|
Adapters::PBSPro.new(pbspro: pbspro, qstat_factor: qstat_factor)
|
25
29
|
end
|
26
30
|
end
|
@@ -41,6 +45,18 @@ module OodCore
|
|
41
45
|
# @return [String, nil] the batch server host
|
42
46
|
attr_reader :host
|
43
47
|
|
48
|
+
# The login node to submit the job via ssh
|
49
|
+
# @example
|
50
|
+
# my_batch.submit_host #=> "my_batch.server.edu"
|
51
|
+
# @return [String, nil] the login node
|
52
|
+
attr_reader :submit_host
|
53
|
+
|
54
|
+
# Whether to use strict host checking when ssh to submit_host
|
55
|
+
# @example
|
56
|
+
# my_batch.strict_host_checking #=> "false"
|
57
|
+
# @return [Bool, true] the login node; true if not present
|
58
|
+
attr_reader :strict_host_checking
|
59
|
+
|
44
60
|
# The path containing the PBS executables
|
45
61
|
# @example
|
46
62
|
# my_batch.pbs_exec.to_s #=> "/usr/local/pbspro/10.0.0
|
@@ -58,11 +74,15 @@ module OodCore
|
|
58
74
|
class Error < StandardError; end
|
59
75
|
|
60
76
|
# @param host [#to_s, nil] the batch server host
|
77
|
+
# @param submit_host [#to_s, nil] the login node to ssh to
|
78
|
+
# @param strict_host_checking [bool, true] wheter to use strict host checking when ssh to submit_host
|
61
79
|
# @param exec [#to_s, nil] path to pbs executables
|
62
|
-
def initialize(host: nil, pbs_exec: nil, bin_overrides: {})
|
63
|
-
@host
|
64
|
-
@
|
65
|
-
@
|
80
|
+
def initialize(host: nil, submit_host: "", strict_host_checking: true, pbs_exec: nil, bin_overrides: {})
|
81
|
+
@host = host && host.to_s
|
82
|
+
@submit_host = submit_host && submit_host.to_s
|
83
|
+
@strict_host_checking = strict_host_checking
|
84
|
+
@pbs_exec = pbs_exec && Pathname.new(pbs_exec.to_s)
|
85
|
+
@bin_overrides = bin_overrides
|
66
86
|
end
|
67
87
|
|
68
88
|
# Get a list of hashes detailing each of the jobs on the batch server
|
@@ -87,7 +107,7 @@ module OodCore
|
|
87
107
|
# @return [Array<Hash>] list of details for jobs
|
88
108
|
def get_jobs(id: "")
|
89
109
|
args = ["-f", "-t"] # display all information
|
90
|
-
args
|
110
|
+
args.concat [id.to_s] unless id.to_s.empty?
|
91
111
|
lines = call("qstat", *args).gsub("\n\t", "").split("\n").map(&:strip)
|
92
112
|
|
93
113
|
jobs = []
|
@@ -159,12 +179,12 @@ module OodCore
|
|
159
179
|
cmd = cmd.to_s
|
160
180
|
bindir = (!!pbs_exec) ? pbs_exec.join("bin").to_s : ''
|
161
181
|
cmd = OodCore::Job::Adapters::Helper.bin_path(cmd, bindir, bin_overrides)
|
162
|
-
args = args.map(&:to_s)
|
163
182
|
env = env.to_h.each_with_object({}) { |(k, v), h| h[k.to_s] = v.to_s }
|
164
183
|
env["PBS_DEFAULT"] = host.to_s if host
|
165
184
|
env["PBS_EXEC"] = pbs_exec.to_s if pbs_exec
|
185
|
+
cmd, args = OodCore::Job::Adapters::Helper.ssh_wrap(submit_host, cmd, args, strict_host_checking)
|
166
186
|
chdir ||= "."
|
167
|
-
o, e, s = Open3.capture3(env, cmd, *args, stdin_data: stdin.to_s, chdir: chdir.to_s)
|
187
|
+
o, e, s = Open3.capture3(env, cmd, *(args.map(&:to_s)), stdin_data: stdin.to_s, chdir: chdir.to_s)
|
168
188
|
s.success? ? o : raise(Error, e)
|
169
189
|
end
|
170
190
|
end
|
@@ -227,28 +247,28 @@ module OodCore
|
|
227
247
|
# Set qsub options
|
228
248
|
args = []
|
229
249
|
# ignore args, can't use these if submitting from STDIN
|
230
|
-
args
|
231
|
-
args
|
232
|
-
args
|
250
|
+
args.concat ["-h"] if script.submit_as_hold
|
251
|
+
args.concat ["-r", script.rerunnable ? "y" : "n"] unless script.rerunnable.nil?
|
252
|
+
args.concat ["-M", script.email.join(",")] unless script.email.nil?
|
233
253
|
if script.email_on_started && script.email_on_terminated
|
234
|
-
args
|
254
|
+
args.concat ["-m", "be"]
|
235
255
|
elsif script.email_on_started
|
236
|
-
args
|
256
|
+
args.concat ["-m", "b"]
|
237
257
|
elsif script.email_on_terminated
|
238
|
-
args
|
258
|
+
args.concat ["-m", "e"]
|
239
259
|
end
|
240
|
-
args
|
241
|
-
args
|
260
|
+
args.concat ["-N", script.job_name] unless script.job_name.nil?
|
261
|
+
args.concat ["-S", script.shell_path] unless script.shell_path.nil?
|
242
262
|
# ignore input_path (not defined in PBS Pro)
|
243
|
-
args
|
244
|
-
args
|
263
|
+
args.concat ["-o", script.output_path] unless script.output_path.nil?
|
264
|
+
args.concat ["-e", script.error_path] unless script.error_path.nil?
|
245
265
|
# Reservations are actually just queues in PBS Pro
|
246
|
-
args
|
247
|
-
args
|
248
|
-
args
|
249
|
-
args
|
250
|
-
args
|
251
|
-
args
|
266
|
+
args.concat ["-q", script.reservation_id] if !script.reservation_id.nil? && script.queue_name.nil?
|
267
|
+
args.concat ["-q", script.queue_name] unless script.queue_name.nil?
|
268
|
+
args.concat ["-p", script.priority] unless script.priority.nil?
|
269
|
+
args.concat ["-a", script.start_time.localtime.strftime("%C%y%m%d%H%M.%S")] unless script.start_time.nil?
|
270
|
+
args.concat ["-A", script.accounting_id] unless script.accounting_id.nil?
|
271
|
+
args.concat ["-l", "walltime=#{seconds_to_duration(script.wall_time)}"] unless script.wall_time.nil?
|
252
272
|
|
253
273
|
# Set dependencies
|
254
274
|
depend = []
|
@@ -256,20 +276,21 @@ module OodCore
|
|
256
276
|
depend << "afterok:#{afterok.join(":")}" unless afterok.empty?
|
257
277
|
depend << "afternotok:#{afternotok.join(":")}" unless afternotok.empty?
|
258
278
|
depend << "afterany:#{afterany.join(":")}" unless afterany.empty?
|
259
|
-
args
|
279
|
+
args.concat ["-W", "depend=#{depend.join(",")}"] unless depend.empty?
|
260
280
|
|
261
281
|
# Set environment variables
|
262
282
|
envvars = script.job_environment.to_h
|
263
|
-
args
|
283
|
+
args.concat ["-v", envvars.map{|k,v| "#{k}=#{v}"}.join(",")] unless envvars.empty?
|
284
|
+
args.concat ["-V"] if script.copy_environment?
|
264
285
|
|
265
286
|
# If error_path is not specified we join stdout & stderr (as this
|
266
287
|
# mimics what the other resource managers do)
|
267
|
-
args
|
288
|
+
args.concat ["-j", "oe"] if script.error_path.nil?
|
268
289
|
|
269
|
-
args
|
290
|
+
args.concat ["-J", script.job_array_request] unless script.job_array_request.nil?
|
270
291
|
|
271
292
|
# Set native options
|
272
|
-
args
|
293
|
+
args.concat script.native if script.native
|
273
294
|
|
274
295
|
# Submit job
|
275
296
|
@pbspro.submit_string(script.content, args: args, chdir: script.workdir)
|
@@ -397,6 +418,10 @@ module OodCore
|
|
397
418
|
raise JobAdapterError, e.message unless /Unknown Job Id/ =~ e.message || /Job has finished/ =~ e.message
|
398
419
|
end
|
399
420
|
|
421
|
+
def directive_prefix
|
422
|
+
'#PBS'
|
423
|
+
end
|
424
|
+
|
400
425
|
private
|
401
426
|
# Convert duration to seconds
|
402
427
|
def duration_in_seconds(time)
|
@@ -15,7 +15,7 @@ end
|
|
15
15
|
class OodCore::Job::Adapters::Sge::Batch
|
16
16
|
using OodCore::Refinements::HashExtensions
|
17
17
|
|
18
|
-
attr_reader :bin, :bin_overrides, :conf, :cluster, :helper
|
18
|
+
attr_reader :bin, :bin_overrides, :conf, :cluster, :helper, :submit_host, :strict_host_checking
|
19
19
|
|
20
20
|
require "ood_core/job/adapters/sge/qstat_xml_j_r_listener"
|
21
21
|
require "ood_core/job/adapters/sge/qstat_xml_r_listener"
|
@@ -33,10 +33,11 @@ class OodCore::Job::Adapters::Sge::Batch
|
|
33
33
|
# @see Factory.build_sge
|
34
34
|
def initialize(config)
|
35
35
|
@cluster = config.fetch(:cluster, nil)
|
36
|
-
@
|
37
|
-
@bin = Pathname.new(config.fetch(:bin, nil))
|
36
|
+
@bin = Pathname.new(config.fetch(:bin, nil).to_s)
|
38
37
|
@sge_root = Pathname.new(config[:sge_root] || ENV['SGE_ROOT'] || "/var/lib/gridengine")
|
39
38
|
@bin_overrides = config.fetch(:bin_overrides, {})
|
39
|
+
@submit_host = config.fetch(:submit_host, "")
|
40
|
+
@strict_host_checking = config.fetch(:strict_host_checking, true)
|
40
41
|
|
41
42
|
# FIXME: hack as this affects env of the process!
|
42
43
|
ENV['SGE_ROOT'] = @sge_root.to_s
|
@@ -63,7 +64,7 @@ class OodCore::Job::Adapters::Sge::Batch
|
|
63
64
|
def get_all(owner: nil)
|
64
65
|
listener = QstatXmlRListener.new
|
65
66
|
argv = ['qstat', '-r', '-xml']
|
66
|
-
argv
|
67
|
+
argv.concat ['-u', owner] unless owner.nil?
|
67
68
|
REXML::Parsers::StreamParser.new(call(*argv), listener).parse
|
68
69
|
|
69
70
|
listener.parsed_jobs.map{
|
@@ -167,11 +168,10 @@ class OodCore::Job::Adapters::Sge::Batch
|
|
167
168
|
# Call a forked SGE command for a given batch server
|
168
169
|
def call(cmd, *args, env: {}, stdin: "", chdir: nil)
|
169
170
|
cmd = OodCore::Job::Adapters::Helper.bin_path(cmd, bin, bin_overrides)
|
170
|
-
args = args.map(&:to_s)
|
171
|
-
|
172
171
|
env = env.to_h.each_with_object({}) { |(k, v), h| h[k.to_s] = v.to_s }
|
172
|
+
cmd, args = OodCore::Job::Adapters::Helper.ssh_wrap(submit_host, cmd, args, strict_host_checking, env)
|
173
173
|
chdir ||= "."
|
174
|
-
o, e, s = Open3.capture3(env, cmd, *args, stdin_data: stdin.to_s, chdir: chdir.to_s)
|
174
|
+
o, e, s = Open3.capture3(env, cmd, *(args.map(&:to_s)), stdin_data: stdin.to_s, chdir: chdir.to_s)
|
175
175
|
s.success? ? o : raise(Error, e)
|
176
176
|
end
|
177
177
|
|
@@ -17,37 +17,38 @@ class OodCore::Job::Adapters::Sge::Helper
|
|
17
17
|
raise_error_on_unsupported_args(script, after: after, afterok: afterok, afternotok: afternotok, afterany: afterany)
|
18
18
|
|
19
19
|
args = []
|
20
|
-
args
|
21
|
-
args
|
22
|
-
script.job_environment.each_pair {|k, v| args
|
20
|
+
args.concat ['-h'] if script.submit_as_hold
|
21
|
+
args.concat ['-r', 'yes'] if script.rerunnable
|
22
|
+
script.job_environment.each_pair {|k, v| args.concat ['-v', "#{k.to_s}=#{v.to_s}"]} unless script.job_environment.nil?
|
23
|
+
args.concat ["-V"] if script.copy_environment?
|
23
24
|
|
24
25
|
if script.workdir
|
25
|
-
args
|
26
|
+
args.concat ['-wd', script.workdir]
|
26
27
|
elsif ! script_contains_wd_directive?(script.content)
|
27
|
-
args
|
28
|
+
args.concat ['-cwd']
|
28
29
|
end
|
29
30
|
|
30
31
|
on_event_email = []
|
31
32
|
on_event_email << 'b' if script.email_on_started # beginning
|
32
33
|
on_event_email << 'ea' if script.email_on_terminated # end, aborted
|
33
34
|
|
34
|
-
args
|
35
|
+
args.concat ['-M', script.email.first, '-m', on_event_email.join] if script.email && ! on_event_email.empty?
|
35
36
|
|
36
37
|
afterok = Array(afterok).map(&:to_s)
|
37
|
-
args
|
38
|
+
args.concat ['-hold_jid_ad', afterok.join(',')] unless afterok.empty?
|
38
39
|
|
39
40
|
# ignoring email_on_started
|
40
|
-
args
|
41
|
-
args
|
42
|
-
args
|
43
|
-
args
|
44
|
-
args
|
45
|
-
args
|
46
|
-
args
|
47
|
-
args
|
48
|
-
args
|
49
|
-
args
|
50
|
-
args
|
41
|
+
args.concat ['-N', script.job_name] unless script.job_name.nil?
|
42
|
+
args.concat ['-e', script.error_path] unless script.error_path.nil?
|
43
|
+
args.concat ['-o', script.output_path] unless script.output_path.nil?
|
44
|
+
args.concat ['-ar', script.reservation_id] unless script.reservation_id.nil?
|
45
|
+
args.concat ['-q', script.queue_name] unless script.queue_name.nil?
|
46
|
+
args.concat ['-p', script.priority] unless script.priority.nil?
|
47
|
+
args.concat ['-a', script.start_time.strftime('%C%y%m%d%H%M.%S')] unless script.start_time.nil?
|
48
|
+
args.concat ['-l', "h_rt=" + seconds_to_duration(script.wall_time)] unless script.wall_time.nil?
|
49
|
+
args.concat ['-P', script.accounting_id] unless script.accounting_id.nil?
|
50
|
+
args.concat ['-t', script.job_array_request] unless script.job_array_request.nil?
|
51
|
+
args.concat Array.wrap(script.native) if script.native
|
51
52
|
|
52
53
|
args
|
53
54
|
end
|
@@ -27,29 +27,44 @@ class QstatXmlJRListener
|
|
27
27
|
@parsed_job = {
|
28
28
|
:tasks => [],
|
29
29
|
:status => :queued,
|
30
|
-
:procs => 1,
|
31
|
-
:native => {
|
30
|
+
:procs => 1,
|
31
|
+
:native => {
|
32
|
+
:ST_name => ''
|
33
|
+
}
|
32
34
|
}
|
33
35
|
@current_text = nil
|
34
36
|
@current_request = nil
|
37
|
+
@processing_JB_stdout_path_list = false
|
35
38
|
|
36
39
|
@processing_job_array_spec = false
|
40
|
+
@adding_slots = false
|
41
|
+
|
37
42
|
@job_array_spec = {
|
38
43
|
start: nil,
|
39
44
|
stop: nil,
|
40
45
|
step: 1, # Step can have a default of 1
|
41
46
|
}
|
42
47
|
@running_tasks = []
|
48
|
+
@native_tags = ['JB_job_number', 'JB_job_name', 'JB_version', 'JB_project', 'JB_exec_file', 'JB_script_file', 'JB_script_size', 'JB_submission_time', 'JB_execution_time', 'JB_deadline', 'JB_owner', 'JB_uid', 'JB_group', 'JB_gid', 'JB_account', 'JB_cwd', 'JB_notify', 'JB_type', 'JB_reserve', 'JB_priority', 'JB_jobshare', 'JB_verify', 'JB_checkpoint_attr', 'JB_checkpoint_interval', 'JB_restart']
|
43
49
|
end
|
44
50
|
|
45
51
|
def tag_start(name, attrs)
|
46
52
|
case name
|
47
53
|
when 'task_id_range'
|
48
54
|
toggle_processing_array_spec
|
55
|
+
when 'JB_pe_range'
|
56
|
+
toggle_adding_slots
|
57
|
+
when 'JB_stdout_path_list'
|
58
|
+
@processing_JB_stdout_path_list = true
|
49
59
|
end
|
50
60
|
end
|
51
61
|
|
52
62
|
def tag_end(name)
|
63
|
+
#Add to native hash if in native_tags
|
64
|
+
if (@native_tags.include?(name))
|
65
|
+
@parsed_job[:native][:"#{name}"] = @current_text
|
66
|
+
end
|
67
|
+
|
53
68
|
case name
|
54
69
|
when 'JB_ja_tasks'
|
55
70
|
end_JB_ja_tasks
|
@@ -78,13 +93,20 @@ class QstatXmlJRListener
|
|
78
93
|
when 'djob_info'
|
79
94
|
finalize_parsed_job
|
80
95
|
when 'RN_min'
|
81
|
-
set_job_array_piece(:start)
|
96
|
+
set_job_array_piece(:start) if @processing_job_array_spec
|
97
|
+
set_slots if @adding_slots
|
82
98
|
when 'RN_max'
|
83
|
-
set_job_array_piece(:stop)
|
99
|
+
set_job_array_piece(:stop) if @processing_job_array_spec
|
84
100
|
when 'RN_step'
|
85
|
-
set_job_array_piece(:step)
|
101
|
+
set_job_array_piece(:step) if @processing_job_array_spec
|
86
102
|
when 'task_id_range'
|
87
103
|
toggle_processing_array_spec
|
104
|
+
when 'JB_pe_range'
|
105
|
+
toggle_adding_slots
|
106
|
+
when 'PN_path'
|
107
|
+
end_PN_path
|
108
|
+
when 'ST_name'
|
109
|
+
end_ST_name
|
88
110
|
end
|
89
111
|
end
|
90
112
|
|
@@ -111,7 +133,7 @@ class QstatXmlJRListener
|
|
111
133
|
end
|
112
134
|
|
113
135
|
def end_JB_submission_time
|
114
|
-
@parsed_job[:submission_time] = @current_text.to_i
|
136
|
+
@parsed_job[:submission_time] = ms_to_seconds(@current_text.to_i)
|
115
137
|
end
|
116
138
|
|
117
139
|
def end_JB_ja_tasks
|
@@ -120,7 +142,7 @@ class QstatXmlJRListener
|
|
120
142
|
|
121
143
|
def end_JAT_start_time
|
122
144
|
@parsed_job[:status] = :running
|
123
|
-
@parsed_job[:dispatch_time] = @current_text.to_i
|
145
|
+
@parsed_job[:dispatch_time] = ms_to_seconds(@current_text.to_i)
|
124
146
|
@parsed_job[:wallclock_time] = Time.now.to_i - @parsed_job[:dispatch_time]
|
125
147
|
end
|
126
148
|
|
@@ -146,6 +168,15 @@ class QstatXmlJRListener
|
|
146
168
|
@running_tasks << @current_text
|
147
169
|
end
|
148
170
|
|
171
|
+
def end_PN_path
|
172
|
+
@parsed_job[:native][:PN_path] = @current_text if @processing_JB_stdout_path_list
|
173
|
+
@processing_JB_stdout_path_list = false
|
174
|
+
end
|
175
|
+
|
176
|
+
def end_ST_name
|
177
|
+
@parsed_job[:native][:ST_name] = @parsed_job[:native][:ST_name] + @current_text + ' '
|
178
|
+
end
|
179
|
+
|
149
180
|
def set_job_array_piece(key)
|
150
181
|
@job_array_spec[key] = @current_text if @processing_job_array_spec
|
151
182
|
end
|
@@ -186,5 +217,20 @@ class QstatXmlJRListener
|
|
186
217
|
def toggle_processing_array_spec
|
187
218
|
@processing_job_array_spec = ! @processing_job_array_spec
|
188
219
|
end
|
189
|
-
end
|
190
220
|
|
221
|
+
def toggle_adding_slots
|
222
|
+
@adding_slots = ! @adding_slots
|
223
|
+
end
|
224
|
+
|
225
|
+
def set_slots
|
226
|
+
@parsed_job[:procs] = @current_text.to_i
|
227
|
+
end
|
228
|
+
|
229
|
+
private
|
230
|
+
|
231
|
+
# Some Grid Engines (like UGE) use milliseconds were others use
|
232
|
+
# seconds past the epoch.
|
233
|
+
def ms_to_seconds(raw)
|
234
|
+
raw.digits.length >= 13 ? raw / 1000 : raw
|
235
|
+
end
|
236
|
+
end
|