X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/7f5a540ea4b1bad1a7b1646543e0cd48ff2af7ba..e02bf11203b85a6baac31584b9ba451c92be21b3:/apps/workbench/app/models/proxy_work_unit.rb diff --git a/apps/workbench/app/models/proxy_work_unit.rb b/apps/workbench/app/models/proxy_work_unit.rb index e7806783eb..d817bba3a4 100644 --- a/apps/workbench/app/models/proxy_work_unit.rb +++ b/apps/workbench/app/models/proxy_work_unit.rb @@ -1,46 +1,58 @@ class ProxyWorkUnit < WorkUnit + require 'time' + attr_accessor :lbl attr_accessor :proxied + attr_accessor :my_children + attr_accessor :unreadable_children def initialize proxied, label - self.lbl = label - self.proxied = proxied + @lbl = label + @proxied = proxied end def label - self.lbl + @lbl end def uuid - self.proxied[:uuid] + get(:uuid) end def modified_by_user_uuid - self.proxied[:modified_by_user_uuid] + get(:modified_by_user_uuid) end def created_at - self.proxied[:created_at] + t = get(:created_at) + t = Time.parse(t) if (t.andand.class == String) + t end def started_at - self.proxied[:started_at] + t = get(:started_at) + t = Time.parse(t) if (t.andand.class == String) + t end def finished_at - self.proxied[:finished_at] + t = get(:finished_at) + t = Time.parse(t) if (t.andand.class == String) + t end def state_label - if ["Running", "RunningOnServer", "RunningOnClient"].include? self.proxied[:state].to_s + state = get(:state) + if ["Running", "RunningOnServer", "RunningOnClient"].include? state "Running" else - self.proxied[:state].to_s + state end end def state_bootstrap_class - case self.proxied[:state] + state = get(:state) + case state when 'Complete' 'success' when 'Failed', 'Cancelled' @@ -53,40 +65,303 @@ class ProxyWorkUnit < WorkUnit end def success? - if self.proxied[:state] == 'Complete' + state = get(:state) + if state == 'Complete' true - elsif self.proxied[:state] == 'Failed' + elsif state == 'Failed' or state == 'Cancelled' false else nil end end - def parameters - self.proxied[:script_parameters] + def child_summary + done = 0 + failed = 0 + todo = 0 + running = 0 + children.each do |c| + case c.state_label + when 'Complete' + done = done+1 + when 'Failed', 'Cancelled' + failed = failed+1 + when 'Running' + running = running+1 + else + todo = todo+1 + end + end + + summary = {} + summary[:done] = done + summary[:failed] = failed + summary[:todo] = todo + summary[:running] = running + summary end - def script - self.proxied[:script] + def child_summary_str + summary = child_summary + summary_txt = '' + + if state_label == 'Running' + done = summary[:done] || 0 + running = summary[:running] || 0 + failed = summary[:failed] || 0 + todo = summary[:todo] || 0 + total = done + running + failed + todo + + if total > 0 + summary_txt += "#{summary[:done]} #{'child'.pluralize(summary[:done])} done," + summary_txt += "#{summary[:failed]} failed," + summary_txt += "#{summary[:running]} running," + summary_txt += "#{summary[:todo]} pending" + end + end + summary_txt end - def repository - self.proxied[:repository] + def progress + state = get(:state) + if state == 'Complete' + return 1.0 + elsif state == 'Failed' or state == 'Cancelled' + return 0.0 + end + + summary = child_summary + return 0.0 if summary.nil? + + done = summary[:done] || 0 + running = summary[:running] || 0 + failed = summary[:failed] || 0 + todo = summary[:todo] || 0 + total = done + running + failed + todo + if total > 0 + (done+failed).to_f / total + else + 0.0 + end end - def script_version - self.proxied[:script_version] + def children + [] end - def supplied_script_version - self.proxied[:supplied_script_version] + def outputs + items = [] + children.each do |c| + items << c.output if c.output + end + if !items.any? + items << get(:output) if get(:output) + end + items end - def runtime_constraints - self.proxied[:runtime_constraints] + def title + "process" end - def children - [] + def has_unreadable_children + @unreadable_children + end + + def readable? + resource_class = ArvadosBase::resource_class_for_uuid(uuid) + resource_class.where(uuid: [uuid]).first rescue nil + end + + def link_to_log + if state_label.in? ["Complete", "Failed", "Cancelled"] + lc = log_collection + if lc + logCollection = Collection.find? lc + if logCollection + ApplicationController.helpers.link_to("Log", "#{uri}#Log") + else + "Log unavailable" + end + end + elsif state_label == "Running" + if readable? + ApplicationController.helpers.link_to("Log", "#{uri}#Log") + else + "Log unavailable" + end + end + end + + def walltime + if state_label != "Queued" + if started_at + ((if finished_at then finished_at else Time.now() end) - started_at) + end + end + end + + def cputime + if state_label != "Queued" + if started_at + (runtime_constraints.andand[:min_nodes] || 1) * ((finished_at || Time.now()) - started_at) + end + end + end + + def queuedtime + if state_label == "Queued" + Time.now - Time.parse(created_at.to_s) + end + end + + def show_child_summary + if state_label == "Running" + if child_summary + child_summary_str + end + end + end + + def is_running? + state_label == 'Running' + end + + def is_paused? + state_label == 'Paused' + end + + def is_finished? + state_label.in? ["Complete", "Failed", "Cancelled"] + end + + def is_failed? + state_label == 'Failed' + end + + def ran_for_str + ran_for = nil + if state_label + ran_for = "It " + if state_label == 'Running' + ran_for << "has run" + else + ran_for << "ran" + end + ran_for << " for" + end + ran_for + end + + def started_and_active_for_str + active_for = nil + + if started_at + active_for_1 = "This #{title} started at " + active_for_2 = "It " + if state_label == 'Complete' + active_for_2 << "completed in " + elsif state_label == 'Failed' + active_for_2 << "failed after " + else + active_for_2 << "has been active for " + end + [active_for_1, active_for_2] + end + end + + def show_runtime + runningtime = ApplicationController.helpers.determine_wallclock_runtime(children) + + walltime = 0 + if started_at + walltime = if finished_at then (finished_at - started_at) else (Time.now - started_at) end + end + + resp = '

' + + if started_at + resp << "This #{title} started at " + resp << ApplicationController.helpers.render_localized_date(started_at) + resp << ". It " + if state_label == 'Complete' + resp << "completed in " + elsif state_label == 'Failed' + resp << "failed after " + else + resp << "has been active for " + end + + if walltime > runningtime + resp << ApplicationController.helpers.render_time(walltime, false) + else + resp << ApplicationController.helpers.render_time(runningtime, false) + end + + if finished_at + resp << " at " + resp << ApplicationController.helpers.render_localized_date(finished_at) + end + resp << "." + else + if state_label + resp << "This #{title} is " + resp << if state_label == 'Running' then 'active' else state_label.downcase end + resp << "." + end + end + + if is_failed? + resp << " Check the Log tab for more detail about why it failed." + end + resp << "

" + + resp << "

" + if state_label + resp << "It " + if state_label == 'Running' + resp << "has run" + else + resp << "ran" + end + resp << " for " + + cpu_time = children.map { |c| + if c.started_at + (c.runtime_constraints.andand[:min_nodes] || 1) * ((c.finished_at || Time.now()) - c.started_at) + else + 0 + end + }.reduce(:+) || 0 + + resp << ApplicationController.helpers.render_time(runningtime, false) + if (walltime - runningtime) > 0 + resp << "(" + resp << ApplicationController.helpers.render_time(walltime - runningtime, false) + resp << "queued)" + end + if cpu_time == 0 + resp << "." + else + resp << " and used " + resp << ApplicationController.helpers.render_time(cpu_time, false) + resp << " of node allocation time (" + resp << (cpu_time/runningtime).round(1).to_s + resp << "⨯ scaling)." + end + end + resp << "

" + + resp + end + + protected + + def get key + if @proxied.respond_to? key + @proxied.send(key) + elsif @proxied.is_a?(Hash) + @proxied[key] + end end end