ood_core 0.11.1 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -24,21 +24,32 @@ class QstatXmlRListener
24
24
  @parsed_jobs = []
25
25
  @current_job = {
26
26
  :tasks => [],
27
- :native => {} # TODO: improve native reporting
27
+ :native => {
28
+ :ST_name => ''
29
+ }
28
30
  }
29
31
  @current_text = nil
32
+ @processing_JB_stdout_path_list = false
30
33
 
31
34
  @current_request = nil
35
+ @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']
32
36
  end
33
37
 
34
38
  def tag_start(name, attributes)
35
39
  case name
36
40
  when 'hard_request'
37
41
  start_hard_request(attributes)
42
+ when "JB_stdout_path_list"
43
+ @processing_JB_stdout_path_list = true
38
44
  end
39
45
  end
40
46
 
41
47
  def tag_end(name)
48
+ #Add text if in native_tags
49
+ if (@native_tags.include?(name))
50
+ @current_job[:native][:"#{name}"] = @current_text
51
+ end
52
+
42
53
  case name
43
54
  when 'job_list'
44
55
  end_job_list
@@ -64,6 +75,10 @@ class QstatXmlRListener
64
75
  end_hard_request
65
76
  when 'tasks'
66
77
  add_child_tasks
78
+ when 'PN_path'
79
+ end_PN_path
80
+ when 'ST_name'
81
+ end_ST_name
67
82
  end
68
83
  end
69
84
 
@@ -130,6 +145,15 @@ class QstatXmlRListener
130
145
  end
131
146
  end
132
147
 
148
+ def end_PN_path
149
+ @current_job[:native][:PN_path] = @current_text if @processing_JB_stdout_path_list
150
+ @processing_JB_stdout_path_list = false
151
+ end
152
+
153
+ def end_ST_name
154
+ @current_job[:native][:ST_name] = @current_job[:native][:ST_name] + @current_text + ' '
155
+ end
156
+
133
157
  # Store a completed job and reset current_job for the next pass
134
158
  def end_job_list
135
159
  @parsed_jobs << @current_job
@@ -145,4 +169,3 @@ class QstatXmlRListener
145
169
  }
146
170
  end
147
171
  end
148
-
@@ -14,13 +14,17 @@ module OodCore
14
14
  # @option config [Object] :conf (nil) Path to the slurm conf
15
15
  # @option config [Object] :bin (nil) Path to slurm client binaries
16
16
  # @option config [#to_h] :bin_overrides ({}) Optional overrides to Slurm client executables
17
+ # @option config [Object] :submit_host ("") Submit job on login node via ssh
18
+ # @option config [Object] :strict_host_checking (true) Whether to use strict host checking when ssh to submit_host
17
19
  def self.build_slurm(config)
18
20
  c = config.to_h.symbolize_keys
19
- cluster = c.fetch(:cluster, nil)
20
- conf = c.fetch(:conf, nil)
21
- bin = c.fetch(:bin, nil)
22
- bin_overrides = c.fetch(:bin_overrides, {})
23
- slurm = Adapters::Slurm::Batch.new(cluster: cluster, conf: conf, bin: bin, bin_overrides: bin_overrides)
21
+ cluster = c.fetch(:cluster, nil)
22
+ conf = c.fetch(:conf, nil)
23
+ bin = c.fetch(:bin, nil)
24
+ bin_overrides = c.fetch(:bin_overrides, {})
25
+ submit_host = c.fetch(:submit_host, "")
26
+ strict_host_checking = c.fetch(:strict_host_checking, true)
27
+ slurm = Adapters::Slurm::Batch.new(cluster: cluster, conf: conf, bin: bin, bin_overrides: bin_overrides, submit_host: submit_host, strict_host_checking: strict_host_checking)
24
28
  Adapters::Slurm.new(slurm: slurm)
25
29
  end
26
30
  end
@@ -62,6 +66,16 @@ module OodCore
62
66
  # @return Hash<String, String>
63
67
  attr_reader :bin_overrides
64
68
 
69
+ # The login node where the job is submitted via ssh
70
+ # @example owens.osc.edu
71
+ # @return [String] The login node
72
+ attr_reader :submit_host
73
+
74
+ # Wheter to use strict host checking when ssh to submit_host
75
+ # @example false
76
+ # @return [Bool]; true if empty
77
+ attr_reader :strict_host_checking
78
+
65
79
  # The root exception class that all Slurm-specific exceptions inherit
66
80
  # from
67
81
  class Error < StandardError; end
@@ -69,11 +83,16 @@ module OodCore
69
83
  # @param cluster [#to_s, nil] the cluster name
70
84
  # @param conf [#to_s, nil] path to the slurm conf
71
85
  # @param bin [#to_s] path to slurm installation binaries
72
- def initialize(cluster: nil, bin: nil, conf: nil, bin_overrides: {})
73
- @cluster = cluster && cluster.to_s
74
- @conf = conf && Pathname.new(conf.to_s)
75
- @bin = Pathname.new(bin.to_s)
76
- @bin_overrides = bin_overrides
86
+ # @param bin_overrides [#to_h] a hash of bin ovverides to be used in job
87
+ # @param submit_host [#to_s] Submits the job on a login node via ssh
88
+ # @param strict_host_checking [Bool] Whether to use strict host checking when ssh to submit_host
89
+ def initialize(cluster: nil, bin: nil, conf: nil, bin_overrides: {}, submit_host: "", strict_host_checking: true)
90
+ @cluster = cluster && cluster.to_s
91
+ @conf = conf && Pathname.new(conf.to_s)
92
+ @bin = Pathname.new(bin.to_s)
93
+ @bin_overrides = bin_overrides
94
+ @submit_host = submit_host.to_s
95
+ @strict_host_checking = strict_host_checking
77
96
  end
78
97
 
79
98
  # Get a list of hashes detailing each of the jobs on the batch server
@@ -148,9 +167,9 @@ module OodCore
148
167
  #TODO: write some barebones test for this? like 2 options and id or no id
149
168
  def squeue_args(id: "", owner: nil, options: [])
150
169
  args = ["--all", "--states=all", "--noconvert"]
151
- args += ["-o", "#{RECORD_SEPARATOR}#{options.join(UNIT_SEPARATOR)}"]
152
- args += ["-u", owner.to_s] unless owner.to_s.empty?
153
- args += ["-j", id.to_s] unless id.to_s.empty?
170
+ args.concat ["-o", "#{RECORD_SEPARATOR}#{options.join(UNIT_SEPARATOR)}"]
171
+ args.concat ["-u", owner.to_s] unless owner.to_s.empty?
172
+ args.concat ["-j", id.to_s] unless id.to_s.empty?
154
173
  args
155
174
  end
156
175
 
@@ -275,11 +294,15 @@ module OodCore
275
294
  # Call a forked Slurm command for a given cluster
276
295
  def call(cmd, *args, env: {}, stdin: "")
277
296
  cmd = OodCore::Job::Adapters::Helper.bin_path(cmd, bin, bin_overrides)
297
+
278
298
  args = args.map(&:to_s)
279
- args += ["-M", cluster] if cluster
299
+ args.concat ["-M", cluster] if cluster
300
+
280
301
  env = env.to_h
281
302
  env["SLURM_CONF"] = conf.to_s if conf
282
- o, e, s = Open3.capture3(env, cmd, *args, stdin_data: stdin.to_s)
303
+
304
+ cmd, args = OodCore::Job::Adapters::Helper.ssh_wrap(submit_host, cmd, args, strict_host_checking)
305
+ o, e, s = Open3.capture3(env, cmd, *(args.map(&:to_s)), stdin_data: stdin.to_s)
283
306
  s.success? ? o : raise(Error, e)
284
307
  end
285
308
 
@@ -358,30 +381,31 @@ module OodCore
358
381
  # Set sbatch options
359
382
  args = []
360
383
  # ignore args, don't know how to do this for slurm
361
- args += ["-H"] if script.submit_as_hold
362
- args += (script.rerunnable ? ["--requeue"] : ["--no-requeue"]) unless script.rerunnable.nil?
363
- args += ["-D", script.workdir.to_s] unless script.workdir.nil?
364
- args += ["--mail-user", script.email.join(",")] unless script.email.nil?
384
+ args.concat ["-H"] if script.submit_as_hold
385
+ args.concat (script.rerunnable ? ["--requeue"] : ["--no-requeue"]) unless script.rerunnable.nil?
386
+ args.concat ["-D", script.workdir.to_s] unless script.workdir.nil?
387
+ args.concat ["--mail-user", script.email.join(",")] unless script.email.nil?
365
388
  if script.email_on_started && script.email_on_terminated
366
- args += ["--mail-type", "ALL"]
389
+ args.concat ["--mail-type", "ALL"]
367
390
  elsif script.email_on_started
368
- args += ["--mail-type", "BEGIN"]
391
+ args.concat ["--mail-type", "BEGIN"]
369
392
  elsif script.email_on_terminated
370
- args += ["--mail-type", "END"]
393
+ args.concat ["--mail-type", "END"]
371
394
  elsif script.email_on_started == false && script.email_on_terminated == false
372
- args += ["--mail-type", "NONE"]
395
+ args.concat ["--mail-type", "NONE"]
373
396
  end
374
- args += ["-J", script.job_name] unless script.job_name.nil?
375
- args += ["-i", script.input_path] unless script.input_path.nil?
376
- args += ["-o", script.output_path] unless script.output_path.nil?
377
- args += ["-e", script.error_path] unless script.error_path.nil?
378
- args += ["--reservation", script.reservation_id] unless script.reservation_id.nil?
379
- args += ["-p", script.queue_name] unless script.queue_name.nil?
380
- args += ["--priority", script.priority] unless script.priority.nil?
381
- args += ["--begin", script.start_time.localtime.strftime("%C%y-%m-%dT%H:%M:%S")] unless script.start_time.nil?
382
- args += ["-A", script.accounting_id] unless script.accounting_id.nil?
383
- args += ["-t", seconds_to_duration(script.wall_time)] unless script.wall_time.nil?
384
- args += ['-a', script.job_array_request] unless script.job_array_request.nil?
397
+ args.concat ["-J", script.job_name] unless script.job_name.nil?
398
+ args.concat ["-i", script.input_path] unless script.input_path.nil?
399
+ args.concat ["-o", script.output_path] unless script.output_path.nil?
400
+ args.concat ["-e", script.error_path] unless script.error_path.nil?
401
+ args.concat ["--reservation", script.reservation_id] unless script.reservation_id.nil?
402
+ args.concat ["-p", script.queue_name] unless script.queue_name.nil?
403
+ args.concat ["--priority", script.priority] unless script.priority.nil?
404
+ args.concat ["--begin", script.start_time.localtime.strftime("%C%y-%m-%dT%H:%M:%S")] unless script.start_time.nil?
405
+ args.concat ["-A", script.accounting_id] unless script.accounting_id.nil?
406
+ args.concat ["-t", seconds_to_duration(script.wall_time)] unless script.wall_time.nil?
407
+ args.concat ['-a', script.job_array_request] unless script.job_array_request.nil?
408
+ args.concat ['--qos', script.qos] unless script.qos.nil?
385
409
  # ignore nodes, don't know how to do this for slurm
386
410
 
387
411
  # Set dependencies
@@ -390,17 +414,14 @@ module OodCore
390
414
  depend << "afterok:#{afterok.join(":")}" unless afterok.empty?
391
415
  depend << "afternotok:#{afternotok.join(":")}" unless afternotok.empty?
392
416
  depend << "afterany:#{afterany.join(":")}" unless afterany.empty?
393
- args += ["-d", depend.join(",")] unless depend.empty?
417
+ args.concat ["-d", depend.join(",")] unless depend.empty?
394
418
 
395
419
  # Set environment variables
396
420
  env = script.job_environment || {}
397
- unless (script.job_environment.nil? || script.job_environment.empty?)
398
- prefix = script.copy_environment? ? "ALL," : "NONE," # NONE if false or nil
399
- args += ["--export", prefix + script.job_environment.keys.join(",")]
400
- end
421
+ args.concat ["--export", export_arg(env, script.copy_environment?)]
401
422
 
402
423
  # Set native options
403
- args += script.native if script.native
424
+ args.concat script.native if script.native
404
425
 
405
426
  # Set content
406
427
  content = if script.shell_path.nil?
@@ -630,6 +651,25 @@ module OodCore
630
651
 
631
652
  Info.new(**parent_task_hash)
632
653
  end
654
+
655
+
656
+ # we default to export NONE, but SLURM defaults to ALL.
657
+ # we do this bc SLURM setups a new environment, loading /etc/profile
658
+ # and all giving 'module' function (among other things shells give),
659
+ # where the PUN did not.
660
+ # --export=ALL export the PUN's environment.
661
+ def export_arg(env, copy_environment)
662
+ if !env.empty? && !copy_environment
663
+ env.keys.join(",")
664
+ elsif !env.empty? && copy_environment
665
+ "ALL," + env.keys.join(",")
666
+ elsif env.empty? && copy_environment
667
+ # only this option changes behaivor dramatically
668
+ "ALL"
669
+ else
670
+ "NONE"
671
+ end
672
+ end
633
673
  end
634
674
  end
635
675
  end
@@ -1,5 +1,6 @@
1
1
  require "ood_core/refinements/hash_extensions"
2
2
  require "ood_core/job/adapters/helper"
3
+ require 'shellwords'
3
4
 
4
5
  module OodCore
5
6
  module Job
@@ -9,16 +10,18 @@ module OodCore
9
10
  # Build the Torque adapter from a configuration
10
11
  # @param config [#to_h] the configuration for job adapter
11
12
  # @option config [#to_s] :host The batch server host
13
+ # @option config [#to_s] :submit_host The login node to submit the job via ssh
12
14
  # @option config [#to_s] :lib ('') Path to torque client libraries
13
15
  # @option config [#to_s] :bin ('') Path to torque client binaries
14
16
  # @option config [#to_h] :custom_bin ({}) Optional overrides to Torque client executables
15
17
  def self.build_torque(config)
16
18
  c = config.to_h.symbolize_keys
17
19
  host = c.fetch(:host) { raise ArgumentError, "No host specified. Missing argument: host" }.to_s
20
+ submit_host = c.fetch(:submit_host, "").to_s
18
21
  lib = c.fetch(:lib, "").to_s
19
22
  bin = c.fetch(:bin, "").to_s
20
23
  custom_bin = c.fetch(:custom_bin, {})
21
- pbs = Adapters::Torque::Batch.new(host: host, lib: lib, bin: bin, custom_bin: custom_bin)
24
+ pbs = Adapters::Torque::Batch.new(host: host, submit_host: submit_host, lib: lib, bin: bin, custom_bin: custom_bin)
22
25
  Adapters::Torque.new(pbs: pbs)
23
26
  end
24
27
  end
@@ -85,7 +88,7 @@ module OodCore
85
88
  depend << "afterany:#{afterany.join(':')}" unless afterany.empty?
86
89
 
87
90
  # Set mailing options
88
- mail_points = ""
91
+ mail_points = ""
89
92
  mail_points += "b" if script.email_on_started
90
93
  mail_points += "e" if script.email_on_terminated
91
94
 
@@ -129,40 +132,44 @@ module OodCore
129
132
  envvars.merge! script.native.fetch(:envvars, {})
130
133
  end
131
134
 
135
+ # Destructively change envvars to shellescape values
136
+ envvars.transform_values! { |v| Shellwords.escape(v) }
137
+
132
138
  # Submit job
133
139
  @pbs.submit_string(script.content, queue: script.queue_name, headers: headers, resources: resources, envvars: envvars)
134
140
  else
135
141
  # Set qsub arguments
136
142
  args = []
137
- args += ["-F", script.args.join(" ")] unless script.args.nil?
138
- args += ["-h"] if script.submit_as_hold
139
- args += ["-r", script.rerunnable ? "y" : "n"] unless script.rerunnable.nil?
140
- args += ["-M", script.email.join(",")] unless script.email.nil?
141
- args += ["-m", mail_points] unless mail_points.empty?
142
- args += ["-N", script.job_name] unless script.job_name.nil?
143
- args += ["-S", script.shell_path] unless script.shell_path.nil?
143
+ args.concat ["-F", script.args.join(" ")] unless script.args.nil?
144
+ args.concat ["-h"] if script.submit_as_hold
145
+ args.concat ["-r", script.rerunnable ? "y" : "n"] unless script.rerunnable.nil?
146
+ args.concat ["-M", script.email.join(",")] unless script.email.nil?
147
+ args.concat ["-m", mail_points] unless mail_points.empty?
148
+ args.concat ["-N", script.job_name] unless script.job_name.nil?
149
+ args.concat ["-S", script.shell_path] unless script.shell_path.nil?
144
150
  # ignore input_path (not defined in Torque)
145
- args += ["-o", script.output_path] unless script.output_path.nil?
146
- args += ["-e", script.error_path] unless script.error_path.nil?
147
- args += ["-W", "x=advres:#{script.reservation_id}"] unless script.reservation_id.nil?
148
- args += ["-q", script.queue_name] unless script.queue_name.nil?
149
- args += ["-p", script.priority] unless script.priority.nil?
150
- args += ["-a", script.start_time.localtime.strftime("%C%y%m%d%H%M.%S")] unless script.start_time.nil?
151
- args += ["-A", script.accounting_id] unless script.accounting_id.nil?
152
- args += ["-W", "depend=#{depend.join(",")}"] unless depend.empty?
153
- args += ["-l", "walltime=#{seconds_to_duration(script.wall_time)}"] unless script.wall_time.nil?
154
- args += ['-t', script.job_array_request] unless script.job_array_request.nil?
151
+ args.concat ["-o", script.output_path] unless script.output_path.nil?
152
+ args.concat ["-e", script.error_path] unless script.error_path.nil?
153
+ args.concat ["-W", "x=advres:#{script.reservation_id}"] unless script.reservation_id.nil?
154
+ args.concat ["-q", script.queue_name] unless script.queue_name.nil?
155
+ args.concat ["-p", script.priority] unless script.priority.nil?
156
+ args.concat ["-a", script.start_time.localtime.strftime("%C%y%m%d%H%M.%S")] unless script.start_time.nil?
157
+ args.concat ["-A", script.accounting_id] unless script.accounting_id.nil?
158
+ args.concat ["-W", "depend=#{depend.join(",")}"] unless depend.empty?
159
+ args.concat ["-l", "walltime=#{seconds_to_duration(script.wall_time)}"] unless script.wall_time.nil?
160
+ args.concat ['-t', script.job_array_request] unless script.job_array_request.nil?
161
+ args.concat ['-l', "qos=#{script.qos}"] unless script.qos.nil?
155
162
  # Set environment variables
156
163
  env = script.job_environment.to_h
157
- args += ["-v", env.keys.join(",")] unless env.empty?
158
- args += ["-V"] if script.copy_environment?
164
+ args.concat ["-v", env.keys.join(",")] unless env.empty?
165
+ args.concat ["-V"] if script.copy_environment?
159
166
 
160
167
  # If error_path is not specified we join stdout & stderr (as this
161
168
  # mimics what the other resource managers do)
162
- args += ["-j", "oe"] if script.error_path.nil?
169
+ args.concat ["-j", "oe"] if script.error_path.nil?
163
170
 
164
171
  # Set native options
165
- args += script.native if script.native
172
+ args.concat script.native if script.native
166
173
 
167
174
  # Submit job
168
175
  @pbs.submit(script.content, args: args, env: env, chdir: script.workdir)
@@ -9,6 +9,18 @@ class OodCore::Job::Adapters::Torque
9
9
  # @return [String] the batch server host
10
10
  attr_reader :host
11
11
 
12
+ # The login node where job is submitted via ssh
13
+ # @example OSC's owens login node
14
+ # my_conn.submit_host #=> "owens.osc.edu"
15
+ # @return [String] the login node
16
+ attr_reader :submit_host
17
+
18
+ # Determines whether to use strict_host_checking for ssh
19
+ # @example
20
+ # my_conn.strict_host_checking.to_s #=> "owens.osc.edu"
21
+ # @return [Bool]
22
+ attr_reader :strict_host_checking
23
+
12
24
  # The path to the Torque client installation libraries
13
25
  # @example For Torque 5.0.0
14
26
  # my_conn.lib.to_s #=> "/usr/local/Torque/5.0.0/lib"
@@ -32,19 +44,23 @@ class OodCore::Job::Adapters::Torque
32
44
  class Error < StandardError; end
33
45
 
34
46
  # @param host [#to_s] the batch server host
47
+ # @param submit_host [#to_s] the login node
48
+ # @param strict_host_checking [bool] use strict host checking when ssh to submit_host
35
49
  # @param lib [#to_s] path to FFI installation libraries
36
50
  # @param bin [#to_s] path to FFI installation binaries
37
- def initialize(host:, lib: "", bin: "", bin_overrides: {}, **_)
38
- @host = host.to_s
39
- @lib = Pathname.new(lib.to_s)
40
- @bin = Pathname.new(bin.to_s)
41
- @bin_overrides = bin_overrides
51
+ def initialize(host:, submit_host: "", strict_host_checking: true, lib: "", bin: "", bin_overrides: {}, **_)
52
+ @host = host.to_s
53
+ @submit_host = submit_host.to_s
54
+ @strict_host_checking = strict_host_checking
55
+ @lib = Pathname.new(lib.to_s)
56
+ @bin = Pathname.new(bin.to_s)
57
+ @bin_overrides = bin_overrides
42
58
  end
43
59
 
44
60
  # Convert object to hash
45
61
  # @return [Hash] the hash describing this object
46
62
  def to_h
47
- {host: host, lib: lib, bin: bin}
63
+ {host: host, submit_host: submit_host, strict_host_checking: strict_host_checking, lib: lib, bin: bin}
48
64
  end
49
65
 
50
66
  # The comparison operator
@@ -437,10 +453,10 @@ class OodCore::Job::Adapters::Torque
437
453
  # NB: The binary includes many useful filters and is preferred
438
454
  def qsub_submit(script, queue, headers, resources, envvars)
439
455
  params = []
440
- params += ["-q", "#{queue}"] unless queue.empty?
441
- params += headers.map {|k,v| qsub_arg(k,v)}.flatten
442
- params += resources.map{|k,v| ["-l", "#{k}=#{v}"]}.flatten
443
- params += ["-v", envvars.map{|k,v| "#{k}=#{v}"}.join(",")] unless envvars.empty?
456
+ params.concat ["-q", "#{queue}"] unless queue.empty?
457
+ params.concat headers.map {|k,v| qsub_arg(k,v)}.flatten
458
+ params.concat resources.map{|k,v| ["-l", "#{k}=#{v}"]}.flatten
459
+ params.concat ["-v", envvars.map{|k,v| "#{k}=#{v}"}.join(",")] unless envvars.empty?
444
460
  params << script
445
461
 
446
462
  env = {
@@ -448,6 +464,7 @@ class OodCore::Job::Adapters::Torque
448
464
  "LD_LIBRARY_PATH" => "#{lib}:#{ENV['LD_LIBRARY_PATH']}"
449
465
  }
450
466
  cmd = OodCore::Job::Adapters::Helper.bin_path('qsub', bin, bin_overrides)
467
+ cmd, params = OodCore::Job::Adapters::Helper.ssh_wrap(submit_host, cmd, params, strict_host_checking, env)
451
468
  o, e, s = Open3.capture3(env, cmd, *params)
452
469
  raise Error, e unless s.success?
453
470
  o.chomp
@@ -456,14 +473,14 @@ class OodCore::Job::Adapters::Torque
456
473
  # Call a forked PBS command for a given host
457
474
  def call(cmd, *args, env: {}, stdin: "", chdir: nil)
458
475
  cmd = OodCore::Job::Adapters::Helper.bin_path(cmd, bin, bin_overrides)
459
- args = args.map(&:to_s)
460
476
  env = env.to_h.each_with_object({}) {|(k,v), h| h[k.to_s] = v.to_s}.merge({
461
477
  "PBS_DEFAULT" => host,
462
478
  "LD_LIBRARY_PATH" => %{#{lib}:#{ENV["LD_LIBRARY_PATH"]}}
463
479
  })
480
+ cmd, args = OodCore::Job::Adapters::Helper.ssh_wrap(submit_host, cmd, args, strict_host_checking, env)
464
481
  stdin = stdin.to_s
465
482
  chdir ||= "."
466
- o, e, s = Open3.capture3(env, cmd, *args, stdin_data: stdin, chdir: chdir.to_s)
483
+ o, e, s = Open3.capture3(env, cmd, *(args.map(&:to_s)), stdin_data: stdin, chdir: chdir.to_s)
467
484
  s.success? ? o : raise(Error, e)
468
485
  end
469
486
  end
@@ -99,6 +99,10 @@ module OodCore
99
99
  # @return [String, nil] job array request
100
100
  attr_reader :job_array_request
101
101
 
102
+ # The qos selected for the job
103
+ # @return [String, nil] qos
104
+ attr_reader :qos
105
+
102
106
  # Object detailing any native specifications that are implementation specific
103
107
  # @note Should not be used at all costs.
104
108
  # @return [Object, nil] native specifications
@@ -130,7 +134,10 @@ module OodCore
130
134
  # @param start_time [#to_i, nil] eligible start time
131
135
  # @param wall_time [#to_i, nil] max real time
132
136
  # @param accounting_id [#to_s, nil] accounting id
137
+ # @param job_array_request [#to_s, nil] job array request
138
+ # @param qos [#to_s, nil] qos
133
139
  # @param native [Object, nil] native specifications
140
+ # @param copy_environment [Boolean, nil] copy the environment
134
141
  def initialize(content:, args: nil, submit_as_hold: nil, rerunnable: nil,
135
142
  job_environment: nil, workdir: nil, email: nil,
136
143
  email_on_started: nil, email_on_terminated: nil,
@@ -138,7 +145,7 @@ module OodCore
138
145
  output_path: nil, error_path: nil, reservation_id: nil,
139
146
  queue_name: nil, priority: nil, start_time: nil,
140
147
  wall_time: nil, accounting_id: nil, job_array_request: nil,
141
- native: nil, copy_environment: nil, **_)
148
+ qos: nil, native: nil, copy_environment: nil, **_)
142
149
  @content = content.to_s
143
150
 
144
151
  @submit_as_hold = submit_as_hold
@@ -162,6 +169,7 @@ module OodCore
162
169
  @wall_time = wall_time && wall_time.to_i
163
170
  @accounting_id = accounting_id && accounting_id.to_s
164
171
  @job_array_request = job_array_request && job_array_request.to_s
172
+ @qos = qos && qos.to_s
165
173
  @native = native
166
174
  @copy_environment = (copy_environment.nil?) ? nil : !! copy_environment
167
175
  end
@@ -191,6 +199,7 @@ module OodCore
191
199
  wall_time: wall_time,
192
200
  accounting_id: accounting_id,
193
201
  job_array_request: job_array_request,
202
+ qos: qos,
194
203
  native: native,
195
204
  copy_environment: copy_environment
196
205
  }