Merge branch '8876-work-unit' into 8650-container-work-unit
[arvados.git] / apps / workbench / app / models / proxy_work_unit.rb
1 class ProxyWorkUnit < WorkUnit
2   require 'time'
3
4   attr_accessor :lbl
5   attr_accessor :proxied
6   attr_accessor :my_children
7   attr_accessor :unreadable_children
8
9   def initialize proxied, label
10     self.lbl = label
11     self.proxied = proxied
12   end
13
14   def label
15     self.lbl
16   end
17
18   def uuid
19     get(:uuid)
20   end
21
22   def modified_by_user_uuid
23     get(:modified_by_user_uuid)
24   end
25
26   def created_at
27     t = get(:created_at)
28     t = Time.parse(t) if (t.andand.class == String)
29     t
30   end
31
32   def started_at
33     t = get(:started_at)
34     t = Time.parse(t) if (t.andand.class == String)
35     t
36   end
37
38   def finished_at
39     t = get(:finished_at)
40     t = Time.parse(t) if (t.andand.class == String)
41     t
42   end
43
44   def state_label
45     state = get(:state)
46     if ["Running", "RunningOnServer", "RunningOnClient"].include? state
47       "Running"
48     else
49       state
50     end
51   end
52
53   def state_bootstrap_class
54     state = get(:state)
55     case state
56     when 'Complete'
57       'success'
58     when 'Failed', 'Cancelled'
59       'danger'
60     when 'Running', 'RunningOnServer', 'RunningOnClient'
61       'info'
62     else
63       'default'
64     end
65   end
66
67   def success?
68     state = get(:state)
69     if state == 'Complete'
70       true
71     elsif state == 'Failed' or state == 'Cancelled'
72       false
73     else
74       nil
75     end
76   end
77
78   def child_summary
79     done = 0
80     failed = 0
81     todo = 0
82     running = 0
83     children.each do |c|
84       case c.state_label
85       when 'Complete'
86         done = done+1
87       when 'Failed', 'Cancelled'
88         failed = failed+1
89       when 'Running'
90         running = running+1
91       else
92         todo = todo+1
93       end
94     end
95
96     summary = {}
97     summary[:done] = done
98     summary[:failed] = failed
99     summary[:todo] = todo
100     summary[:running] = running
101     summary
102   end
103
104   def child_summary_str
105     summary = child_summary
106     summary_txt = ''
107
108     if state_label == 'Running'
109       done = summary[:done] || 0
110       running = summary[:running] || 0
111       failed = summary[:failed] || 0
112       todo = summary[:todo] || 0
113       total = done + running + failed + todo
114
115       if total > 0
116         summary_txt += "#{summary[:done]} #{'child'.pluralize(summary[:done])} done,"
117         summary_txt += "#{summary[:failed]} failed,"
118         summary_txt += "#{summary[:running]} running,"
119         summary_txt += "#{summary[:todo]} pending"
120       end
121     end
122     summary_txt
123   end
124
125   def progress
126     state = get(:state)
127     if state == 'Complete'
128       return 1.0
129     elsif state == 'Failed' or state == 'Cancelled'
130       return 0.0
131     end
132
133     summary = child_summary
134     return 0.0 if summary.nil?
135
136     done = summary[:done] || 0
137     running = summary[:running] || 0
138     failed = summary[:failed] || 0
139     todo = summary[:todo] || 0
140     total = done + running + failed + todo
141     if total > 0
142       (done+failed).to_f / total
143     else
144       0.0
145     end
146   end
147
148   def parameters
149     get(:script_parameters)
150   end
151
152   def repository
153     get(:repository)
154   end
155
156   def script
157     get(:script)
158   end
159
160   def script_version
161     get(:script_version)
162   end
163
164   def supplied_script_version
165     get(:supplied_script_version)
166   end
167
168   def docker_image
169     get(:docker_image_locator)
170   end
171
172   def nondeterministic
173     get(:nondeterministic)
174   end
175
176   def runtime_constraints
177     get(:runtime_constraints)
178   end
179
180   def priority
181     get(:priority)
182   end
183
184   def log_collection
185     get(:log)
186   end
187
188   def output
189     get(:output)
190   end
191
192   def children
193     []
194   end
195
196   def title
197     "process"
198   end
199
200   def has_unreadable_children
201     self.unreadable_children
202   end
203
204   def readable?
205     resource_class = ArvadosBase::resource_class_for_uuid(uuid)
206     resource_class.where(uuid: [uuid]).first rescue nil
207   end
208
209   def link_to_log
210     if state_label.in? ["Complete", "Failed", "Cancelled"]
211       lc = log_collection
212       if lc
213         logCollection = Collection.find? lc
214         if logCollection
215           ApplicationController.helpers.link_to("Log", "#{uri}#Log")
216         else
217           "Log unavailable"
218         end
219       end
220     elsif state_label == "Running"
221       if readable?
222         ApplicationController.helpers.link_to("Log", "#{uri}#Log")
223       else
224         "Log unavailable"
225       end
226     end
227   end
228
229   def walltime
230     if state_label != "Queued"
231       if started_at
232         ((if finished_at then finished_at else Time.now() end) - started_at)
233       end
234     end
235   end
236
237   def cputime
238     if state_label != "Queued"
239       if started_at
240         (runtime_constraints.andand[:min_nodes] || 1) *
241              ((finished_at || Time.now()) - started_at)
242       end
243     end
244   end
245
246   def queuedtime
247     if state_label == "Queued"
248       Time.now - Time.parse(created_at.to_s)
249     end
250   end
251
252   def show_child_summary
253     if state_label == "Running"
254       if child_summary
255         child_summary_str
256       end
257     end
258   end
259
260   def is_running?
261     state_label == 'Running'
262   end
263
264   def is_paused?
265     state_label == 'Paused'
266   end
267
268   def is_finished?
269     state_label.in? ["Complete", "Failed", "Cancelled"]
270   end
271
272   def is_failed?
273     state_label == 'Failed'
274   end
275
276   def can_be_canceled?
277     state_label.in? ["Queued", "Running"] and can_cancel?
278   end
279
280   def ran_for_str
281     ran_for = nil
282     if state_label
283       ran_for = "It "
284       if state_label == 'Running'
285         ran_for << "has run"
286       else
287         ran_for << "ran"
288       end
289       ran_for << " for"
290     end
291     ran_for
292   end
293
294   def started_and_active_for_str
295     active_for = nil
296
297     if started_at
298       active_for_1 = "This #{title} started at "
299       active_for_2 = "It "
300       if state_label == 'Complete'
301         active_for_2 << "completed in "
302       elsif state_label == 'Failed'
303         active_for_2 << "failed after "
304       else
305         active_for_2 << "has been active for "
306       end
307       [active_for_1, active_for_2]
308     end
309   end
310
311   protected
312
313   def get key
314     if self.proxied.respond_to? key
315       self.proxied.send(key)
316     elsif self.proxied.is_a?(Hash)
317       self.proxied[key]
318     end
319   end
320 end