Merge branch 'master' into 10645-cr-mounts-display
[arvados.git] / apps / workbench / app / models / proxy_work_unit.rb
index 1cf92e2cd6fafbdc2816d04ce94a2aaabeb4ad8d..b7cc6a0f196951f19472ace07acc37d244500b94 100644 (file)
@@ -6,38 +6,53 @@ class ProxyWorkUnit < WorkUnit
   attr_accessor :my_children
   attr_accessor :unreadable_children
 
-  def initialize proxied, label
-    self.lbl = label
-    self.proxied = proxied
+  def initialize proxied, label, parent
+    @lbl = label
+    @proxied = proxied
+    @parent = parent
   end
 
   def label
-    self.lbl
+    @lbl
   end
 
   def uuid
     get(:uuid)
   end
 
+  def parent
+    @parent
+  end
+
   def modified_by_user_uuid
     get(:modified_by_user_uuid)
   end
 
+  def owner_uuid
+    get(:owner_uuid)
+  end
+
   def created_at
     t = get(:created_at)
-    t = Time.parse(t) if (t.andand.class == String)
+    t = Time.parse(t) if (t.is_a? String)
     t
   end
 
   def started_at
     t = get(:started_at)
-    t = Time.parse(t) if (t.andand.class == String)
+    t = Time.parse(t) if (t.is_a? String)
+    t
+  end
+
+  def modified_at
+    t = get(:modified_at)
+    t = Time.parse(t) if (t.is_a? String)
     t
   end
 
   def finished_at
     t = get(:finished_at)
-    t = Time.parse(t) if (t.andand.class == String)
+    t = Time.parse(t) if (t.is_a? String)
     t
   end
 
@@ -45,13 +60,15 @@ class ProxyWorkUnit < WorkUnit
     state = get(:state)
     if ["Running", "RunningOnServer", "RunningOnClient"].include? state
       "Running"
+    elsif state == 'New'
+      "Not started"
     else
       state
     end
   end
 
   def state_bootstrap_class
-    state = get(:state)
+    state = state_label
     case state
     when 'Complete'
       'success'
@@ -65,10 +82,10 @@ class ProxyWorkUnit < WorkUnit
   end
 
   def success?
-    state = get(:state)
+    state = state_label
     if state == 'Complete'
       true
-    elsif state == 'Failed'
+    elsif state == 'Failed' or state == 'Cancelled'
       false
     else
       nil
@@ -123,10 +140,10 @@ class ProxyWorkUnit < WorkUnit
   end
 
   def progress
-    state = get(:state)
+    state = state_label
     if state == 'Complete'
       return 1.0
-    elsif state == 'Failed' or state== 'Cancelled'
+    elsif state == 'Failed' or state == 'Cancelled'
       return 0.0
     end
 
@@ -145,74 +162,166 @@ class ProxyWorkUnit < WorkUnit
     end
   end
 
-  def parameters
-    get(:script_parameters)
+  def children
+    []
   end
 
-  def repository
-    get(:repository)
+  def outputs
+    []
   end
 
-  def script
-    get(:script)
+  def title
+    "process"
   end
 
-  def script_version
-    get(:script_version)
+  def has_unreadable_children
+    @unreadable_children
   end
 
-  def supplied_script_version
-    get(:supplied_script_version)
+  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 runtime_constraints
-    get(:runtime_constraints)
+  def cputime
+    if children.any?
+      children.map { |c|
+        c.cputime
+      }.reduce(:+) || 0
+    else
+      if started_at
+        (runtime_constraints.andand[:min_nodes] || 1).to_i * ((finished_at || Time.now()) - started_at)
+      else
+        0
+      end
+    end
   end
 
-  def docker_image
-    get(:docker_image_locator)
+  def queuedtime
+    if state_label == "Queued"
+      Time.now - Time.parse(created_at.to_s)
+    end
   end
 
-  def nondeterministic
-    get(:nondeterministic)
+  def is_running?
+    state_label == 'Running'
   end
 
-  def priority
-    get(:priority)
+  def is_paused?
+    state_label == 'Paused'
   end
 
-  def log_collection
-    get(:log)
+  def is_finished?
+    state_label.in? ["Complete", "Failed", "Cancelled"]
   end
 
-  def output
-    get(:output)
+  def is_failed?
+    state_label == 'Failed'
   end
 
-  def children
-    []
-  end
+  def show_runtime
+    runningtime = ApplicationController.helpers.determine_wallclock_runtime(if children.any? then children else [self] end)
 
-  def title
-    "work unit"
+    walltime = 0
+    if started_at
+      walltime = if finished_at then (finished_at - started_at) else (Time.now - started_at) end
+    end
+
+    resp = '<p>'
+
+    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 << "</p>"
+
+    resp << "<p>"
+    if state_label
+      resp << "It "
+      if state_label == 'Running'
+        resp << "has run"
+      else
+        resp << "ran"
+      end
+      resp << " for "
+
+      cpu_time = cputime
+
+      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 << "&Cross; scaling)."
+      end
+    end
+    resp << "</p>"
+
+    resp
   end
 
-  def has_unreadable_children
-    self.unreadable_children
+  def log_object_uuids
+    [uuid]
   end
 
-  def readable?
-    resource_class = ArvadosBase::resource_class_for_uuid(uuid)
-    resource_class.where(uuid: [uuid]).first rescue nil
+  def live_log_lines(limit)
+    Log.where(object_uuid: log_object_uuids).
+      order("created_at DESC").
+      limit(limit).
+      with_count('none').
+      select { |log| log.properties[:text].is_a? String }.
+      reverse.
+      flat_map { |log| log.properties[:text].split("\n") }
   end
 
   protected
 
-  def get key
-    if self.proxied.respond_to? key
-      self.proxied.send(key)
-    elsif self.proxied.is_a?(Hash)
-      self.proxied[key]
+  def get key, obj=@proxied
+    if obj.respond_to? key
+      obj.send(key)
+    elsif obj.is_a?(Hash)
+      obj[key] || obj[key.to_s]
     end
   end
 end