Merge branch '8650-container-work-unit' into 9318-dashboard-uses-work-units
[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 outputs
193     items = []
194     children.each do |c|
195       items << c.output if c.output
196     end
197     if !items.any?
198       items << get(:output) if get(:output)
199     end
200     items
201   end
202
203   def children
204     []
205   end
206
207   def title
208     "process"
209   end
210
211   def has_unreadable_children
212     self.unreadable_children
213   end
214
215   def readable?
216     resource_class = ArvadosBase::resource_class_for_uuid(uuid)
217     resource_class.where(uuid: [uuid]).first rescue nil
218   end
219
220   def link_to_log
221     if state_label.in? ["Complete", "Failed", "Cancelled"]
222       lc = log_collection
223       if lc
224         logCollection = Collection.find? lc
225         if logCollection
226           ApplicationController.helpers.link_to("Log", "#{uri}#Log")
227         else
228           "Log unavailable"
229         end
230       end
231     elsif state_label == "Running"
232       if readable?
233         ApplicationController.helpers.link_to("Log", "#{uri}#Log")
234       else
235         "Log unavailable"
236       end
237     end
238   end
239
240   def walltime
241     if state_label != "Queued"
242       if started_at
243         ((if finished_at then finished_at else Time.now() end) - started_at)
244       end
245     end
246   end
247
248   def cputime
249     if state_label != "Queued"
250       if started_at
251         (runtime_constraints.andand[:min_nodes] || 1) *
252              ((finished_at || Time.now()) - started_at)
253       end
254     end
255   end
256
257   def queuedtime
258     if state_label == "Queued"
259       Time.now - Time.parse(created_at.to_s)
260     end
261   end
262
263   def show_child_summary
264     if state_label == "Running"
265       if child_summary
266         child_summary_str
267       end
268     end
269   end
270
271   def is_running?
272     state_label == 'Running'
273   end
274
275   def is_paused?
276     state_label == 'Paused'
277   end
278
279   def is_finished?
280     state_label.in? ["Complete", "Failed", "Cancelled"]
281   end
282
283   def is_failed?
284     state_label == 'Failed'
285   end
286
287   def can_be_canceled?
288     state_label.in? ["Queued", "Running"] and can_cancel?
289   end
290
291   def ran_for_str
292     ran_for = nil
293     if state_label
294       ran_for = "It "
295       if state_label == 'Running'
296         ran_for << "has run"
297       else
298         ran_for << "ran"
299       end
300       ran_for << " for"
301     end
302     ran_for
303   end
304
305   def started_and_active_for_str
306     active_for = nil
307
308     if started_at
309       active_for_1 = "This #{title} started at "
310       active_for_2 = "It "
311       if state_label == 'Complete'
312         active_for_2 << "completed in "
313       elsif state_label == 'Failed'
314         active_for_2 << "failed after "
315       else
316         active_for_2 << "has been active for "
317       end
318       [active_for_1, active_for_2]
319     end
320   end
321
322   protected
323
324   def get key
325     if self.proxied.respond_to? key
326       self.proxied.send(key)
327     elsif self.proxied.is_a?(Hash)
328       self.proxied[key]
329     end
330   end
331 end