Merge branch '15361-acr-create-workflow' refs #15361
[arvados.git] / apps / workbench / app / models / container_work_unit.rb
1 # Copyright (C) The Arvados Authors. All rights reserved.
2 #
3 # SPDX-License-Identifier: AGPL-3.0
4
5 class ContainerWorkUnit < ProxyWorkUnit
6   attr_accessor :container
7   attr_accessor :child_proxies
8
9   def initialize proxied, label, parent, child_objects=nil
10     super proxied, label, parent
11     if @proxied.is_a?(ContainerRequest)
12       container_uuid = get(:container_uuid)
13       if container_uuid
14         @container = Container.find(container_uuid)
15       end
16     end
17     @container = nil if !defined?(@container)
18     @child_proxies = child_objects
19   end
20
21   def children
22     return @my_children if @my_children
23
24     items = []
25     container_uuid = if @proxied.is_a?(Container) then uuid else get(:container_uuid) end
26     if container_uuid
27       cols = ContainerRequest.columns.map(&:name) - %w(id updated_at mounts secret_mounts runtime_token)
28       my_children = @child_proxies || ContainerRequest.select(cols).where(requesting_container_uuid: container_uuid).with_count("none").results if !my_children
29       my_child_containers = my_children.map(&:container_uuid).compact.uniq
30       grandchildren = {}
31       my_child_containers.each { |c| grandchildren[c] = []} if my_child_containers.any?
32       reqs = ContainerRequest.select(cols).where(requesting_container_uuid: my_child_containers).with_count("none").results if my_child_containers.any?
33       reqs.each {|cr| grandchildren[cr.requesting_container_uuid] << cr} if reqs
34
35       my_children.each do |cr|
36         items << cr.work_unit(cr.name || 'this container', child_objects=grandchildren[cr.container_uuid])
37       end
38     end
39
40     @child_proxies = nil #no need of this any longer
41     @my_children = items
42   end
43
44   def title
45     "container"
46   end
47
48   def uri
49     uuid = get(:uuid)
50
51     return nil unless uuid
52
53     if @proxied.class.respond_to? :table_name
54       "/#{@proxied.class.table_name}/#{uuid}"
55     else
56       resource_class = ArvadosBase.resource_class_for_uuid(uuid)
57       "#{resource_class.table_name}/#{uuid}" if resource_class
58     end
59   end
60
61   def can_cancel?
62     @proxied.is_a?(ContainerRequest) &&
63       @proxied.state == "Committed" &&
64       (@proxied.priority > 0 || get(:state, @container) != 'Running') &&
65       @proxied.editable?
66   end
67
68   def container_uuid
69     get(:container_uuid)
70   end
71
72   def requesting_container_uuid
73     get(:requesting_container_uuid)
74   end
75
76   def priority
77     @proxied.priority
78   end
79
80   # For the following properties, use value from the @container if exists
81   # This applies to a ContainerRequest with container_uuid
82
83   def started_at
84     t = get_combined(:started_at)
85     t = Time.parse(t) if (t.is_a? String)
86     t
87   end
88
89   def modified_at
90     t = get_combined(:modified_at)
91     t = Time.parse(t) if (t.is_a? String)
92     t
93   end
94
95   def finished_at
96     t = get_combined(:finished_at)
97     t = Time.parse(t) if (t.is_a? String)
98     t
99   end
100
101   def state_label
102     if get(:state) == 'Final' && get(:state, @container) != 'Complete'
103       # Request was finalized before its container started (or the
104       # container was cancelled)
105       return 'Cancelled'
106     end
107     state = get(:state, @container) || get(:state, @proxied)
108     case state
109     when 'Locked', 'Queued'
110       if priority == 0
111         'On hold'
112       else
113         'Queued'
114       end
115     when 'Complete'
116       if exit_code == 0
117         state
118       else
119         'Failed'
120       end
121     when 'Running'
122       if runtime_status[:error]
123         'Failing'
124       elsif runtime_status[:warning]
125         'Warning'
126       else
127         state
128       end
129     else
130       # Cancelled, or Uncommitted (no container assigned)
131       state
132     end
133   end
134
135   def runtime_status
136     return get(:runtime_status, @container) || get(:runtime_status, @proxied)
137   end
138
139   def state_bootstrap_class
140     case state_label
141     when 'Failing'
142       'danger'
143     when 'Warning'
144       'warning'
145     else
146       super
147     end
148   end
149
150   def exit_code
151     get_combined(:exit_code)
152   end
153
154   def docker_image
155     get_combined(:container_image)
156   end
157
158   def runtime_constraints
159     get_combined(:runtime_constraints)
160   end
161
162   def log_collection
163     if @proxied.is_a?(ContainerRequest)
164       get(:log_uuid)
165     else
166       get(:log)
167     end
168   end
169
170   def outputs
171     items = []
172     if @proxied.is_a?(ContainerRequest)
173       out = get(:output_uuid)
174     else
175       out = get(:output)
176     end
177     items << out if out
178     items
179   end
180
181   def command
182     get_combined(:command)
183   end
184
185   def cwd
186     get_combined(:cwd)
187   end
188
189   def environment
190     env = get_combined(:environment)
191     env = nil if env.andand.empty?
192     env
193   end
194
195   def mounts
196     mnt = get_combined(:mounts)
197     mnt = nil if mnt.andand.empty?
198     mnt
199   end
200
201   def output_path
202     get_combined(:output_path)
203   end
204
205   def log_object_uuids
206     [get(:uuid, @container), get(:uuid, @proxied)].compact
207   end
208
209   def render_log
210     collection = Collection.find(log_collection) rescue nil
211     if collection
212       return {log: collection, partial: 'collections/show_files', locals: {object: collection, no_checkboxes: true}}
213     end
214   end
215
216   def template_uuid
217     properties = get(:properties)
218     if properties
219       properties[:template_uuid]
220     end
221   end
222
223   # End combined properties
224
225   protected
226   def get_combined key
227     from_container = get(key, @container)
228     from_proxied = get(key, @proxied)
229
230     if from_container.is_a? Hash or from_container.is_a? Array
231       if from_container.any? then from_container else from_proxied end
232     else
233       from_container || from_proxied
234     end
235   end
236 end