rbbt-util 5.26.157 → 5.26.158

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.
@@ -1,310 +0,0 @@
1
- module WorkflowRESTClient
2
- def self.encode(url)
3
- begin
4
- URI.encode(url)
5
- rescue
6
- Log.warn $!.message
7
- url
8
- end
9
- end
10
-
11
- def self.fix_hash(hash, fix_values = false)
12
- fixed = {}
13
- hash.each do |key, value|
14
- fixed[key.to_sym] = case value
15
- when TrueClass
16
- value
17
- when FalseClass
18
- value
19
- when Hash
20
- fix_hash(value)
21
- when (fix_values and String )
22
- value.to_sym
23
- when IO
24
- value.read
25
- when TSV::Dumper
26
- value.stream
27
- when Step
28
- stream = get_stream(value)
29
- stream || value.load
30
- else
31
- value
32
- end
33
- end
34
- fixed
35
- end
36
-
37
- def self.parse_exception(text)
38
- klass, message = text.split " => "
39
- begin
40
- klass = Kernel.const_get klass
41
- return klass.new message
42
- rescue
43
- message
44
- end
45
- end
46
-
47
- def self.capture_exception
48
- begin
49
- yield
50
- rescue Exception => e
51
- raise e unless e.respond_to? :response
52
- begin
53
- ne = parse_exception e.response.to_s
54
- case ne
55
- when String
56
- raise e.class, ne
57
- when Exception
58
- raise ne
59
- else
60
- raise
61
- end
62
- rescue
63
- raise e
64
- end
65
- raise $!
66
- end
67
- end
68
-
69
- def self.fix_params(params)
70
- new_params = {}
71
- params.each do |k,v|
72
- if Array === v and v.empty?
73
- new_params[k] = "EMPTY_ARRAY"
74
- else
75
- new_params[k] = v
76
- end
77
- end
78
- new_params
79
- end
80
-
81
- def self.clean_url(url, params = {})
82
- params = params.merge({ :_format => 'json', :update => 'clean' })
83
- params = fix_params params
84
- res = capture_exception do
85
- Misc.insist(2, 0.5) do
86
- Log.debug{ "RestClient clean: #{ url } - #{Misc.fingerprint params}" }
87
- res = begin
88
- RestClient.get(self.encode(url), :params => params)
89
- rescue RestClient::NotFound
90
- return nil
91
- end
92
- raise TryAgain if res.code == 202
93
- res
94
- end
95
- end
96
- res
97
- end
98
-
99
- def self.get_raw(url, params = {})
100
- params = params.merge({ :_format => 'raw' })
101
- params = fix_params params
102
- res = capture_exception do
103
- Misc.insist(2, 0.5) do
104
- raise "No url" if url.nil?
105
- Log.debug{ "RestClient get_raw: #{ url } - #{Misc.fingerprint params}" }
106
- res = RestClient.get(self.encode(url), :params => params)
107
- raise TryAgain if res.code == 202
108
- res.to_s
109
- end
110
- end
111
- res
112
- end
113
-
114
- def self.get_json(url, params = {})
115
- Log.debug{ "RestClient get_json: #{ url } - #{Misc.fingerprint params }" }
116
- params = params.merge({ :_format => 'json' })
117
- params = fix_params params
118
-
119
- res = capture_exception do
120
- Misc.insist(2, 0.5) do
121
- RestClient.get(self.encode(url), :params => params)
122
- end
123
- end
124
-
125
- begin
126
- JSON.parse(res)
127
- rescue
128
- res
129
- end
130
- end
131
-
132
- def self.post_jobname(url, params = {})
133
- Log.debug{ "RestClient post_jobname: #{ url } - #{Misc.fingerprint params}" }
134
- params = params.merge({ :_format => 'jobname' })
135
- params = fix_params params
136
-
137
- WorkflowRESTClient.__prepare_inputs_for_restclient(params)
138
- name = capture_exception do
139
- RestClient.post(self.encode(url), params)
140
- end
141
-
142
- Log.debug{ "RestClient jobname returned for #{ url } - #{Misc.fingerprint params}: #{name}" }
143
-
144
- name
145
- end
146
-
147
- def self.post_json(url, params = {})
148
- if url =~ /_cache_type=:exec/
149
- JSON.parse(Open.open(url, :nocache => true))
150
- else
151
- params = params.merge({ :_format => 'json' })
152
- params = fix_params params
153
-
154
- res = capture_exception do
155
- RestClient.post(self.encode(url), params)
156
- end
157
-
158
- begin
159
- JSON.parse(res)
160
- rescue
161
- res
162
- end
163
- end
164
- end
165
-
166
- def get
167
- params ||= {}
168
- params = params.merge(:_format => [:string, :boolean, :tsv, :annotations, :array].include?(result_type.to_sym) ? :raw : :json )
169
- @cache_result ||= Persist.persist("REST persist", :binary, :file => cache_file + "." + Misc.obj2digest(params)) do
170
- Misc.insist 3, rand(2) + 1 do
171
- begin
172
- init_job if url.nil?
173
- @adaptor.get_raw(url, params)
174
- rescue
175
- Log.exception $!
176
- raise $!
177
- end
178
- end
179
- end
180
- end
181
-
182
- def load
183
- params = {}
184
- join unless done? or streaming?
185
- raise get_exception if error? or aborted?
186
- load_res get
187
- end
188
-
189
- def exec_job
190
- res = _run_job(:exec)
191
- load_res res, result_type == :array ? :json : result_type
192
- end
193
-
194
- def abort
195
- return self if status == :done
196
- @adaptor.get_json(@url + '?_update=abort') if @url and @name
197
- self
198
- end
199
-
200
- def init_job(cache_type = nil, other_params = {})
201
- cache_type = :asynchronous if cache_type.nil? and not @is_exec
202
- cache_type = :exec if cache_type.nil?
203
- @last_info_time = nil
204
- @done = false
205
- get_streams
206
- @name ||= Persist.memory("RemoteSteps", :workflow => self, :task => task, :jobname => @name, :inputs => inputs, :cache_type => cache_type) do
207
- Misc.insist do
208
- @adaptor.post_jobname(File.join(base_url, task.to_s), inputs.merge(other_params).merge(:jobname => @name||@base_name, :_cache_type => cache_type))
209
- end
210
- end
211
- if Open.remote? @name
212
- @url = @name
213
- @name = File.basename(@name)
214
- else
215
- @url = File.join(base_url, task.to_s, @name)
216
- end
217
- self
218
- end
219
-
220
- def recursive_clean
221
- Log.warn "Not doing recursive cleans"
222
- return
223
- begin
224
- _restart
225
- params = {:_update => :recursive_clean}
226
- @adaptor.get_raw(url, params)
227
- rescue Exception
228
- Log.exception $!
229
- end
230
- self
231
- end
232
-
233
- def _clean
234
- begin
235
- _restart
236
- cache_files.each do |cache_file|
237
- Open.rm cache_file
238
- end
239
- params = {:_update => :clean}
240
- @adaptor.clean_url(url, params) if @url
241
- rescue Exception
242
- Log.exception $!
243
- end
244
- end
245
-
246
- def clean
247
- init_job
248
- _clean
249
- self
250
- end
251
-
252
- def stream_job(task_url, task_params, stream_input, cache_type = :exec)
253
- require 'rbbt/util/misc/multipart_payload'
254
- WorkflowRESTClient.capture_exception do
255
- @streaming = true
256
-
257
- Log.debug{ "RestClient stream #{Process.pid}: #{ task_url } #{stream_input} #{cache_type} - #{Misc.fingerprint task_params}" }
258
- res = RbbtMutiplartPayload.issue task_url, task_params, stream_input, nil, nil, true
259
- type = res.gets
260
-
261
- out = case type.strip
262
- when "LOCATION"
263
- @url = res.gets
264
- @url.sub!(/\?.*/,'')
265
- join
266
- WorkflowRESTClient.get_raw(@url)
267
- @done = true
268
- @streaming = false
269
- when /STREAM: (.*)/
270
- @url = $1.strip
271
- res.callback = Proc.new do
272
- Log.medium "Done streaming result from #{@url}"
273
- @done = true
274
- @streaming = false
275
- end
276
- res
277
- when "BULK"
278
- begin
279
- res.read
280
- ensure
281
- @done = true
282
- @streaming = false
283
- end
284
- else
285
- raise "What? " + type
286
- end
287
-
288
- ConcurrentStream.setup(out, :filename => @url)
289
-
290
- out
291
- end
292
- end
293
-
294
- def _run_job(cache_type = :async)
295
- get_streams
296
-
297
- task_url = URI.encode(File.join(base_url, task.to_s))
298
- @adaptor.__prepare_inputs_for_restclient(inputs)
299
- task_params = inputs.merge(:_cache_type => cache_type, :jobname => base_name, :_format => [:string, :boolean, :tsv, :annotations].include?(result_type) ? :raw : :json)
300
-
301
- if cache_type == :stream or cache_type == :exec and stream_input and inputs[stream_input]
302
- io = self.stream_job(task_url, task_params, stream_input, cache_type)
303
- return io
304
- else
305
- @adaptor.execute_job(base_url, task, task_params, cache_type)
306
- end
307
-
308
- end
309
-
310
- end
@@ -1,61 +0,0 @@
1
- require 'rbbt/workflow/remote/ssh/driver'
2
-
3
- module WorkflowSSHClient
4
- def workflow_description
5
- WorkflowSSHClient.get_raw(File.join(url, 'description'))
6
- end
7
-
8
- def documentation
9
- @documention ||= IndiferentHash.setup(WorkflowSSHClient.get_json(File.join(url, "documentation")))
10
- @documention
11
- end
12
-
13
- def task_info(task)
14
- @task_info ||= IndiferentHash.setup({})
15
-
16
- if @task_info[task].nil?
17
- task_info = WorkflowSSHClient.get_json(File.join(@base_url, task.to_s))
18
- task_info = WorkflowSSHClient.fix_hash(task_info)
19
-
20
- task_info[:result_type] = task_info[:result_type].to_sym if task_info[:result_type]
21
- task_info[:export] = task_info[:export].to_sym if task_info[:export]
22
- task_info[:input_types] = WorkflowSSHClient.fix_hash(task_info[:input_types], true)
23
- task_info[:inputs] = task_info[:inputs].collect{|input| input.to_sym }
24
-
25
- @task_info[task] = IndiferentHash.setup(task_info)
26
- end
27
-
28
- IndiferentHash.setup(@task_info[task])
29
- end
30
-
31
- def tasks
32
- @tasks ||= Hash.new do |hash,task_name|
33
- info = @task_info[task_name]
34
- task = Task.setup info do |*args|
35
- raise "This is a remote task"
36
- end
37
- task.name = task_name.to_sym
38
- hash[task_name] = task
39
- end
40
- end
41
-
42
- def load_tasks
43
- @task_info.keys.each{|name| tasks[name]}
44
- end
45
-
46
- def task_dependencies
47
- @task_dependencies ||= Hash.new do |hash,task|
48
- hash[task] = if exported_tasks.include? task
49
- WorkflowSSHClient.get_json(File.join(url, task.to_s, 'dependencies'))
50
- else
51
- []
52
- end
53
- end
54
- end
55
-
56
- def init_remote_tasks
57
- @task_info = IndiferentHash.setup(WorkflowSSHClient.get_json(url))
58
- @exec_exports = @stream_exports = @synchronous_exports = []
59
- @asynchronous_exports = @task_info.keys
60
- end
61
- end
@@ -1,147 +0,0 @@
1
- module SSHDriver
2
- def self.run(server, script)
3
- Log.debug "Run ssh script in #{server}:\n#{script}"
4
- CMD.cmd("ssh '#{server}' 'shopt -s expand_aliases; bash -l -i -c \"ruby\"' ", :in => script, :log => true).read
5
- end
6
-
7
- #def self.run_log(server, script)
8
- # Log.debug "Run and monitor ssh script in #{server}:\n#{script}"
9
- # CMD.cmd("ssh '#{server}' 'shopt -s expand_aliases; bash -ic \"ruby\"' ", :in => script, :log => true)
10
- #end
11
-
12
- def self.parse_url(url)
13
- m = url.match(/ssh:\/\/([^:]+):(.*)/)
14
- server = m.captures[0]
15
- path = m.captures[1]
16
- [server, path]
17
- end
18
-
19
- def self.path_script(path)
20
-
21
- workflow, task, job, *rest = path.split("/")
22
-
23
- script =<<-EOF
24
- require 'rbbt/workflow'
25
- wf = Workflow.require_workflow "#{workflow}"
26
- EOF
27
-
28
- case task
29
- when nil
30
- script +=<<-EOF
31
- task_info = {}
32
- wf.tasks.keys.each do |task|
33
- task_info[task] = wf.task_info(task)
34
- end
35
- res = task_info
36
- EOF
37
- when 'documentation'
38
- script +=<<-EOF
39
- res = documentation = wf.documentation
40
- EOF
41
- else
42
- if job.nil?
43
- script +=<<-EOF
44
- task = '#{task}'
45
- res = task_info = wf.task_info(task)
46
- EOF
47
- else
48
- case rest.first
49
- when nil
50
- script +=<<-EOF
51
- task = '#{task}'
52
- jobname = '#{job}'
53
- res = job = wf.fast_load_id(File.join(task, jobname))
54
- EOF
55
- when "info"
56
- script +=<<-EOF
57
- task = '#{task}'
58
- jobname = '#{job}'
59
- job = wf.fast_load_id(File.join(task, jobname))
60
- res = job_info = job.info
61
- EOF
62
- else
63
- raise "Unkown path: #{[path, rest].inspect}"
64
- end
65
- end
66
- end
67
- end
68
-
69
- def self.job_script(inputs_id, jobname = nil)
70
- script =<<-EOF
71
- jobname = #{jobname.nil? ? 'nil' : "'#{jobname}'"}
72
- path = File.join(ENV["HOME"], '.rbbt/tmp/tmp-ssh_job_inputs/#{inputs_id}')
73
- job_inputs = Workflow.load_inputs(path, task_info[:inputs], task_info[:input_types])
74
- job = wf.job(task, jobname, job_inputs)
75
- EOF
76
- script
77
- end
78
-
79
- def self.get_json(url, params)
80
- server, path = parse_url(url)
81
- script = path_script(path)
82
-
83
- script +=<<-EOF
84
- STDOUT.write res.to_json
85
- EOF
86
-
87
- JSON.parse(self.run(server, script))
88
- end
89
-
90
- def self.get_raw(url, params)
91
- server, path = parse_url(url)
92
- script = path_script(path)
93
-
94
- script +=<<-EOF
95
- STDOUT.write res
96
- EOF
97
-
98
- self.run(server, script)
99
- end
100
-
101
- def self.post_job(url, inputs_id, jobname = nil)
102
- server, path = parse_url(url)
103
-
104
- script = path_script(path)
105
- script += job_script(inputs_id, jobname)
106
- script +=<<-EOF
107
- job.init_info
108
- STDOUT.write job.name
109
- EOF
110
- @name = self.run(server, script)
111
- end
112
-
113
- def self.run_job(url, input_id, jobname = nil)
114
- server, path = parse_url(url)
115
-
116
- script = path_script(path)
117
- script += job_script(input_id, jobname)
118
- script +=<<-EOF
119
- job.produce
120
- STDOUT.write job.path
121
- EOF
122
- self.run(server, script)
123
- end
124
-
125
- def self.run_slurm_job(url, input_id, jobname = nil)
126
- server, path = parse_url(url)
127
-
128
- script = path_script(path)
129
- script += job_script(input_id, jobname)
130
- script +=<<-EOF
131
- job.produce
132
- STDOUT.write job.path
133
- EOF
134
- self.run(server, script)
135
- end
136
-
137
- def self.clean(url, input_id, jobname = nil)
138
- server, path = parse_url(url)
139
-
140
- script = path_script(path)
141
- script +=<<-EOF
142
- job.clean
143
- EOF
144
- self.run(server, script)
145
- end
146
-
147
- end
@@ -1,193 +0,0 @@
1
- module WorkflowSSHClient
2
- attr_accessor :override_dependencies
3
-
4
- def self.fix_hash(hash, fix_values = false)
5
- fixed = {}
6
- hash.each do |key, value|
7
- fixed[key.to_sym] = case value
8
- when TrueClass
9
- value
10
- when FalseClass
11
- value
12
- when Hash
13
- fix_hash(value)
14
- when (fix_values and String )
15
- value.to_sym
16
- when IO
17
- value.read
18
- when TSV::Dumper
19
- value.stream
20
- when Step
21
- stream = get_stream(value)
22
- stream || value.load
23
- else
24
- value
25
- end
26
- end
27
- fixed
28
- end
29
-
30
- def self.parse_exception(text)
31
- klass, message = text.split " => "
32
- begin
33
- klass = Kernel.const_get klass
34
- return klass.new message
35
- rescue
36
- message
37
- end
38
- end
39
-
40
- def self.capture_exception
41
- begin
42
- yield
43
- rescue Exception => e
44
- raise e unless e.respond_to? :response
45
- begin
46
- ne = parse_exception e.response.to_s
47
- case ne
48
- when String
49
- raise e.class, ne
50
- when Exception
51
- raise ne
52
- else
53
- raise
54
- end
55
- rescue
56
- raise e
57
- end
58
- raise $!
59
- end
60
- end
61
-
62
- def self.fix_params(params)
63
- new_params = {}
64
- params.each do |k,v|
65
- if Array === v and v.empty?
66
- new_params[k] = "EMPTY_ARRAY"
67
- else
68
- new_params[k] = v
69
- end
70
- end
71
- new_params
72
- end
73
-
74
- def self.get_json(url, params = {})
75
- Log.debug{ "SSHClient get_json: #{ url } - #{Misc.fingerprint params }" }
76
- params = params.merge({ :_format => 'json' })
77
- params = fix_params params
78
-
79
- res = capture_exception do
80
- Misc.insist(2, 0.5) do
81
- SSHDriver.get_json(url, :params => params)
82
- end
83
- end
84
-
85
- begin
86
- JSON.parse(res)
87
- rescue
88
- res
89
- end
90
- end
91
-
92
- def self.upload_inputs(server, inputs, input_types, input_id)
93
- TmpFile.with_file do |dir|
94
- if Step.save_inputs(inputs, input_types, dir)
95
- CMD.cmd("ssh '#{server}' mkdir -p .rbbt/tmp/tmp-ssh_job_inputs/; scp -r '#{dir}' #{server}:.rbbt/tmp/tmp-ssh_job_inputs/#{input_id}")
96
- end
97
- end
98
- end
99
-
100
- #{{{ RUN
101
-
102
-
103
- def init_job(cache_type = nil, other_params = {})
104
- cache_type = :asynchronous if cache_type.nil? and not @is_exec
105
- cache_type = :exec if cache_type.nil?
106
- @last_info_time = nil
107
- @done = false
108
- @server, @server_path = SSHDriver.parse_url base_url
109
- @input_id ||= "inputs-" << rand(100000).to_s
110
- @input_types = task_info(task)[:input_types]
111
-
112
- if override_dependencies
113
-
114
- if override_dependencies && override_dependencies.any?
115
- override_dependencies.each do |od|
116
- name, _sep, value = od.partition("=")
117
- inputs[name] = value
118
- end
119
- end
120
- iii inputs
121
-
122
- WorkflowSSHClient.upload_inputs(@server, inputs, @input_types, @input_id)
123
- else
124
- WorkflowSSHClient.upload_inputs(@server, inputs, @input_types, @input_id)
125
- end
126
-
127
- @name ||= Persist.memory("RemoteSteps", :workflow => self, :task => task, :jobname => @name, :inputs => inputs, :cache_type => cache_type) do
128
- Misc.insist do
129
- input_types = {}
130
- SSHDriver.post_job(File.join(base_url, task.to_s), @input_id, @base_name)
131
- end
132
- end
133
- if Open.remote? @name
134
- @url = @name
135
- @name = File.basename(@name)
136
- else
137
- @url = File.join(base_url, task.to_s, @name)
138
- end
139
- self
140
- end
141
-
142
- def path
143
- @server, @server_path = SSHDriver.parse_url @base_url
144
- "ssh://" + @server + ":" + @remote_path
145
- end
146
-
147
- def produce(*args)
148
- input_types = {}
149
- init_job
150
- @remote_path = SSHDriver.run_job(File.join(base_url, task.to_s), @input_id, @base_name)
151
- while ! done?
152
- sleep 1
153
- end
154
- end
155
-
156
- def load
157
- load_res Open.open(path)
158
- end
159
-
160
- def run(*args)
161
- produce(*args)
162
- self.load unless args.first
163
- end
164
-
165
- def clean
166
- init_job
167
- SSHDriver.clean(@url, @input_id, @base_name) if done?
168
- _restart
169
- end
170
-
171
- def self.relay(workflow, task, jobname, inputs, server, options = {})
172
- options = Misc.add_defaults options, :search_path => 'user'
173
- search_path = options[:search_path]
174
-
175
- job = workflow.job(task, jobname, inputs)
176
-
177
- job.dependencies.each do |dep|
178
- dep.produce
179
- end
180
-
181
- override_dependencies = job.dependencies.collect{|dep| [dep.workflow.to_s, dep.task_name.to_s] * "#" << "=" << Rbbt.identify(dep.path)}
182
-
183
- job.dependencies.each do |dep|
184
- Step.migrate(dep.path, search_path, :target => server)
185
- end
186
-
187
- remote = WorkflowRemoteClient.new("ssh://#{server}:#{workflow.to_s}", "#{workflow.to_s}")
188
- rjob = remote.job(task, jobname, {})
189
- rjob.override_dependencies = override_dependencies
190
- rjob.run
191
- end
192
-
193
- end