[ARVADOS] created: 7f5a540ea4b1bad1a7b1646543e0cd48ff2af7ba

Git user git at public.curoverse.com
Fri May 20 23:40:46 EDT 2016


        at  7f5a540ea4b1bad1a7b1646543e0cd48ff2af7ba (commit)


commit 7f5a540ea4b1bad1a7b1646543e0cd48ff2af7ba
Author: radhika <radhika at curoverse.com>
Date:   Fri May 20 23:40:00 2016 -0400

    8876: work_unit views in progress

diff --git a/apps/workbench/app/helpers/pipeline_instances_helper.rb b/apps/workbench/app/helpers/pipeline_instances_helper.rb
index 8fafbc2..b2486c1 100644
--- a/apps/workbench/app/helpers/pipeline_instances_helper.rb
+++ b/apps/workbench/app/helpers/pipeline_instances_helper.rb
@@ -70,8 +70,8 @@ module PipelineInstancesHelper
     timestamps = []
     jobs.each do |j|
       insert_at = 0
-      started_at = j[:started_at]
-      finished_at = (if j[:finished_at] then j[:finished_at] else Time.now end)
+      started_at = j.started_at
+      finished_at = (if j.finished_at then j.finished_at else Time.now end)
       if started_at
         timestamps = merge_range timestamps, started_at, finished_at
       end
diff --git a/apps/workbench/app/models/job_work_unit.rb b/apps/workbench/app/models/job_work_unit.rb
index 2a5cb98..8246e8a 100644
--- a/apps/workbench/app/models/job_work_unit.rb
+++ b/apps/workbench/app/models/job_work_unit.rb
@@ -42,7 +42,7 @@ class JobWorkUnit < ProxyWorkUnit
   end
 
   def log_collection
-    [self.proxied.log]
+    self.proxied.log
   end
 
   def output
diff --git a/apps/workbench/app/models/pipeline_instance_work_unit.rb b/apps/workbench/app/models/pipeline_instance_work_unit.rb
index 3f8c9a2..94990ee 100644
--- a/apps/workbench/app/models/pipeline_instance_work_unit.rb
+++ b/apps/workbench/app/models/pipeline_instance_work_unit.rb
@@ -5,7 +5,7 @@ class PipelineInstanceWorkUnit < ProxyWorkUnit
     jobs = {}
     results = Job.where(uuid: self.proxied.job_ids.values).results
     results.each do |j|
-      jobs[j.uuid] = j.work_unit("job #{items.size}")
+      jobs[j.uuid] = j
     end
 
     components = self.proxied.components
@@ -13,7 +13,7 @@ class PipelineInstanceWorkUnit < ProxyWorkUnit
       if c.is_a?(Hash)
         job = c[:job]
         if job and job[:uuid] and jobs[job[:uuid]]
-          items << jobs[job[:uuid]]
+          items << jobs[job[:uuid]].work_unit(name)
         else
           items << ProxyWorkUnit.new(c, name)
         end
@@ -48,8 +48,4 @@ class PipelineInstanceWorkUnit < ProxyWorkUnit
       0.0
     end
   end
-
-  def log_collection
-    self.proxied.job_log_ids
-  end
 end
diff --git a/apps/workbench/app/models/proxy_work_unit.rb b/apps/workbench/app/models/proxy_work_unit.rb
index 502e6d2..e780678 100644
--- a/apps/workbench/app/models/proxy_work_unit.rb
+++ b/apps/workbench/app/models/proxy_work_unit.rb
@@ -33,9 +33,9 @@ class ProxyWorkUnit < WorkUnit
 
   def state_label
     if ["Running", "RunningOnServer", "RunningOnClient"].include? self.proxied[:state].to_s
-      "running"
+      "Running"
     else
-      self.proxied[:state].to_s.downcase
+      self.proxied[:state].to_s
     end
   end
 
@@ -70,7 +70,7 @@ class ProxyWorkUnit < WorkUnit
     self.proxied[:script]
   end
 
-  def script_repository
+  def repository
     self.proxied[:repository]
   end
 
@@ -85,4 +85,8 @@ class ProxyWorkUnit < WorkUnit
   def runtime_constraints
     self.proxied[:runtime_constraints]
   end
+
+  def children
+    []
+  end
 end
diff --git a/apps/workbench/app/models/work_unit.rb b/apps/workbench/app/models/work_unit.rb
index 00f1435..4185519 100644
--- a/apps/workbench/app/models/work_unit.rb
+++ b/apps/workbench/app/models/work_unit.rb
@@ -60,8 +60,8 @@ class WorkUnit
     # returns script for this work unit, if any
   end
 
-  def script_repository
-    # returns this work unit's script_repository, if any
+  def repository
+    # returns this work unit's script repository, if any
   end
 
   def script_version
diff --git a/apps/workbench/app/views/jobs/_show_status.html.erb b/apps/workbench/app/views/jobs/_show_status.html.erb
index 8075209..8d54b20 100644
--- a/apps/workbench/app/views/jobs/_show_status.html.erb
+++ b/apps/workbench/app/views/jobs/_show_status.html.erb
@@ -8,8 +8,7 @@
    pj[:progress_bar] = render(partial: "job_progress",
                               locals: {:j => @object })
    tasks = JobTask.filter([['job_uuid', '=', @object.uuid]]).results
-   render(partial: 'pipeline_instances/running_component',
-          locals: { tasks: tasks, pj: pj, i: 0, expanded: true})
+   render(partial: 'work_unit/show_component', locals: {wu: @object.work_unit(@object[:name] || "this job")})
 %>
 
 <div class="panel panel-default">
diff --git a/apps/workbench/app/views/pipeline_instances/_show_components.html.erb b/apps/workbench/app/views/pipeline_instances/_show_components.html.erb
index dae57aa..4196558 100644
--- a/apps/workbench/app/views/pipeline_instances/_show_components.html.erb
+++ b/apps/workbench/app/views/pipeline_instances/_show_components.html.erb
@@ -9,7 +9,7 @@
        data-object-uuids="<%= @object.uuid %> <%= job_uuids.join(' ') %>"
        ></div>
 
-  <%= render_pipeline_components("running", :json) %>
+  <%= render partial: 'work_unit/show_component', locals: {wu: @object.work_unit(@object.name)} %>
 
 <% else %>
   <%# state is either New or Ready %>
diff --git a/apps/workbench/app/views/work_unit/_component_detail.html.erb b/apps/workbench/app/views/work_unit/_component_detail.html.erb
new file mode 100644
index 0000000..045154a
--- /dev/null
+++ b/apps/workbench/app/views/work_unit/_component_detail.html.erb
@@ -0,0 +1,91 @@
+      <div class="container">
+        <div class="row">
+          <div class="col-md-5">
+            <table>
+              <% [:uuid, :modified_by_user_uuid, :created_at, :started_at, :finished_at, :priority].each do |k| %>
+                <% val = current_obj.send(k) if current_obj.respond_to?(k) %>
+                <% unless val.nil? %>
+                <tr>
+                  <td style="padding-right: 1em">
+                    <%= k.to_s %>:
+                  </td>
+                  <td>
+                    <% if k == :uuid %>
+                      <%= link_to_arvados_object_if_readable(val, val, link_text: val) %>
+                    <% elsif k.to_s.end_with? 'uuid' %>
+                      <%= link_to_arvados_object_if_readable(val, val, friendly_name: true) %>
+                    <% elsif k.to_s.end_with? '_at' %>
+                      <%= render_localized_date(val) %>
+                    <% else %>
+                      <%= val %>
+                    <% end %>
+                  </td>
+                </tr>
+                <% end %>
+              <% end %>
+            </table>
+          </div>
+          <div class="col-md-6">
+            <table>
+              <% # link to repo tree/file only if the repo is readable
+                 # and the commit is a sha1...
+                 repo =
+                 (/^[0-9a-f]{40}$/ =~ current_obj.script_version and
+                 Repository.where(name: current_obj.repository).first)
+
+                 # ...and the api server provides an http:// or https:// url
+                 repo = nil unless repo.andand.http_fetch_url
+                 %>
+              <% [:script, :repository, :script_version, :supplied_script_version, :nondeterministic].each do |k| %>
+                <% val = current_obj.send(k) if current_obj.respond_to?(k) %>
+                <% unless val.nil? %>
+                <tr>
+                  <td style="padding-right: 1em">
+                    <%= k.to_s %>:
+                  </td>
+                  <td>
+                    <% if repo and k == :repository %>
+                      <%= link_to val, show_repository_tree_path(id: repo.uuid, commit: current_obj.script_version, path: '/') %>
+                    <% elsif repo and k == :script %>
+                      <%= link_to val, show_repository_blob_path(id: repo.uuid, commit: current_obj.script_version, path: 'crunch_scripts/'+current_obj.script) %>
+                    <% elsif repo and k == :script_version %>
+                      <%= link_to val, show_repository_commit_path(id: repo.uuid, commit: current_obj.script_version) %>
+                    <% else %>
+                      <%= val %>
+                    <% end %>
+                  </td>
+                </tr>
+                <% end %>
+              <% end %>
+              <% if current_obj.runtime_constraints.andand[:docker_image] and current_obj.docker_image %>
+                <tr>
+                  <td style="padding-right: 1em">
+                    docker_image:
+                  </td>
+                  <td>
+                    <%= current_obj.runtime_constraints[:docker_image] %>
+                  </td>
+                </tr>
+                <tr>
+                  <td style="padding-right: 1em">
+                    docker_image_locator:
+                  </td>
+                  <td>
+                    <%= link_to_arvados_object_if_readable(current_obj.docker_image,
+                      current_obj.docker_image, friendly_name: true) %>
+                  </td>
+                </tr>
+              <% end %>
+            </table>
+          </div>
+        </div>
+        <% unless current_obj.parameters.nil? %>
+        <div class="row">
+          <div class="col-md-6">
+            <p>script_parameters:</p>
+            <pre><%= JSON.pretty_generate(current_obj.parameters) rescue nil %></pre>
+          </div>
+        </div>
+        <% end %>
+      </div>
+    </div>
diff --git a/apps/workbench/app/views/work_unit/_show_child.html.erb b/apps/workbench/app/views/work_unit/_show_child.html.erb
new file mode 100644
index 0000000..10c6ac0
--- /dev/null
+++ b/apps/workbench/app/views/work_unit/_show_child.html.erb
@@ -0,0 +1,103 @@
+<div class="panel panel-default">
+  <div class="panel-heading">
+    <div class="container-fluid">
+      <div class="row-fluid">
+        <%# column offset 0 %>
+        <div class="col-md-2" style="word-break:break-all;">
+          <h4 class="panel-title">
+            <a data-toggle="collapse" href="#collapse<%= i %>">
+              <%= current_obj.label %> <span class="caret"></span>
+            </a>
+          </h4>
+        </div>
+
+        <%# column offset 2 %>
+        <div class="col-md-2 pipeline-instance-spacing">
+          <%= current_obj.progress %>
+        </div>
+
+        <%# column offset 4 %>
+        <% if not current_obj %>
+          <div class="col-md-8"></div>
+        <% else %>
+          <div class="col-md-1">
+              <% if current_obj.state_label.in? ["Complete", "Failed", "Cancelled"] %>
+                <% if current_obj.log_collection %>
+                  <% logCollection = Collection.find? current_obj.log_collection %>
+                  <% if logCollection %>
+                    <%= link_to "Log", job_path(current_obj.uuid, anchor: "Log") %>
+                  <% else %>
+                    Log unavailable
+                  <% end %>
+                <% end %>
+              <% elsif current_obj.state_label == "Running" %>
+                <% job = Job.find? current_obj.uuid %>
+                <% if job %>
+                  <%= link_to "Log", job_path(current_obj.uuid, anchor: "Log") %>
+                <% else %>
+                  Log unavailable
+                <% end %>
+              <% end %>
+          </div>
+
+          <%# column offset 5 %>
+          <% if current_obj.state_label != "Queued" %>
+          <div class="col-md-3">
+            <% if current_obj.started_at %>
+              <% walltime = ((if current_obj.finished_at then current_obj.finished_at else Time.now() end) - current_obj.started_at) %>
+              <% cputime = (current_obj.runtime_constraints.andand[:min_nodes] || 1) *
+                           ((current_obj.finished_at || Time.now()) - current_obj.started_at) %>
+              <%= render_runtime(walltime, false) %>
+              <% if cputime > 0 %> / <%= render_runtime(cputime, false) %> (<%= (cputime/walltime).round(1) %>⨯)<% end %>
+            <% end %>
+          </div>
+          <% end %>
+
+          <% if current_obj.state_label == "Queued" %>
+            <%# column offset 5 %>
+            <div class="col-md-6">
+              <% queuetime = Time.now - Time.parse(current_obj.created_at.to_s) %>
+              Queued for <%= render_runtime(queuetime, false) %>.
+            </div>
+          <% elsif current_obj.state_label == "Running" %>
+            <%# column offset 8 %>
+            <div class="col-md-3">
+              <span class="task-summary-status">
+                <%= current_obj.tasks_summary[:done] %> <%= "task".pluralize(current_obj.tasks_summary[:done]) %> done,
+                <%= current_obj.tasks_summary[:failed] %> failed,
+                <%= current_obj.tasks_summary[:running] %> running,
+                <%= current_obj.tasks_summary[:todo] %> pending
+              </span>
+            </div>
+          <% elsif current_obj.state_label.in? ["Complete", "Failed", "Cancelled"] %>
+            <%# column offset 8 %>
+            <div class="col-md-4 text-overflow-ellipsis">
+              <% if current_obj.output %>
+                <%= link_to_arvados_object_if_readable(current_obj.output, 'Output data not available', friendly_name: true) %>
+              <% elsif current_obj.output %>
+                <%= link_to_arvados_object_if_readable(current_obj.output, 'Output data not available', link_text: "Output of #{current_obj.label}") %>
+              <% else %>
+                No output.
+              <% end %>
+            </div>
+          <% end %>
+
+          <% if current_obj.state_label.in? ["Queued", "Running"] and @object.editable? %>
+            <%# column offset 11 %>
+            <div class="col-md-1 pipeline-instance-spacing">
+              <%= form_tag "/jobs/#{current_obj.uuid}/cancel", remote: true, style: "display:inline; padding-left: 1em" do |f| %>
+                <%= hidden_field_tag :return_to, url_for(@object) %>
+                <%= button_tag "Cancel", {class: 'btn btn-xs btn-danger', id: "cancel-job-button"} %>
+              <% end %>
+            </div>
+          <% end %>
+        <% end %>
+      </div>
+    </div>
+  </div>
+
+  <div id="collapse<%= i %>" class="panel-collapse collapse <%= if expanded then 'in' end %>">
+    <div class="panel-body">
+      <%= render partial: 'work_unit/show_component', locals: {wu: current_obj} %>
+  </div>
+</div>
diff --git a/apps/workbench/app/views/work_unit/_show_component.html.erb b/apps/workbench/app/views/work_unit/_show_component.html.erb
new file mode 100644
index 0000000..0e650ac
--- /dev/null
+++ b/apps/workbench/app/views/work_unit/_show_component.html.erb
@@ -0,0 +1,105 @@
+<%# Work unit status %>
+
+<div class="pull-right" style="padding-left: 1em">
+  Current state: <span class="badge badge-<%= wu.state_bootstrap_class %>" data-wu-state="<%= wu.state_label %>">
+    <% if wu.state_label == "running" %>
+      Active
+    <% else %>
+      <%= wu.state_label %>
+    <% end %>
+  </span> 
+</div>
+
+<% if wu.state_label == 'Paused' %>
+  <p>
+    This work unit is paused. Work unit children that are
+    already running will continue to run, but no new work units will be submitted.
+  </p>
+<% end %>
+
+<% runningtime = determine_wallclock_runtime(wu.children) %>
+
+<p>
+  <% if wu.started_at %>
+    This work unit started at <%= render_localized_date(wu.started_at) %>.
+    It
+    <% if wu.state_label == 'Complete' %>
+      completed in
+    <% elsif wu.state_label == 'Failed' %>
+      failed after
+    <% else %>
+      has been active for
+    <% end %>
+
+    <% walltime = if wu.finished_at then
+                    wu.finished_at - wu.started_at
+                  else
+                    Time.now - wu.started_at
+                  end %>
+
+    <%= if walltime > runningtime
+          render_runtime(walltime, false)
+        else
+          render_runtime(runningtime, false)
+        end %><% if wu.finished_at %> at <%= render_localized_date(wu.finished_at) %><% end %>.
+    <% else %>
+      It is <%= if wu.state_label == 'Running' then 'active' else wu.state.downcase end %>.
+        <% walltime = 0%>
+    <% end %>
+
+  <% if wu.state_label == 'Failed' %>
+    Check the Log tab for more detail about why it failed.
+  <% end %>
+</p>
+
+<p>
+    It
+    <% if wu.state_label == 'Running' %>
+      has run
+    <% else %>
+      ran
+    <% end %>
+    for
+    <%
+        cputime = wu.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 %>
+    <%= render_runtime(runningtime, false) %><% if (walltime - runningtime) > 0 %>
+      (<%= render_runtime(walltime - runningtime, false) %> queued)<% end %><% if cputime == 0 %>.<% else %>
+      and used
+    <%= render_runtime(cputime, false) %>
+    of node allocation time (<%= (cputime/runningtime).round(1) %>⨯ scaling).
+    <% end %>
+</p>
+
+<p>
+  <%= render partial: 'work_unit/component_detail', locals: {current_obj: wu} %>
+</p>
+
+<%# Work unit children %>
+
+<%
+  job_uuids = wu.children.collect {|c| c.uuid}.compact
+  if job_uuids.any?
+    resource_class = resource_class_for_uuid(job_uuids.first, friendly_name: true)
+    preload_objects_for_dataclass resource_class, job_uuids
+  end
+
+  job_collections = wu.children.collect {|j| j.output}.compact
+  job_collections.concat wu.children.collect {|j| j.docker_image}.uniq.compact
+  job_collections_pdhs = job_collections.select {|x| !(m = CollectionsHelper.match(x)).nil?}.uniq.compact
+  job_collections_uuids = job_collections - job_collections_pdhs
+  preload_collections_for_objects job_collections_uuids if job_collections_uuids.any?
+  preload_for_pdhs job_collections_pdhs if job_collections_pdhs.any?
+%>
+
+<% @descendent_count = 0 if !@descendent_count %>
+
+<% wu.children.each_with_index do |c, i| %>
+  <% @descendent_count += 1 %>
+  <%= render partial: 'work_unit/show_child', locals: {current_obj: c, i: @descendent_count, expanded: false} %>
+<% end %>
diff --git a/apps/workbench/test/unit/work_unit_test.rb b/apps/workbench/test/unit/work_unit_test.rb
index 66b4d9c..63f6a5a 100644
--- a/apps/workbench/test/unit/work_unit_test.rb
+++ b/apps/workbench/test/unit/work_unit_test.rb
@@ -2,10 +2,10 @@ require 'test_helper'
 
 class WorkUnitTest < ActiveSupport::TestCase
   [
-    [Job, 'running_job_with_components', "jwu", 2, "running", nil, 0.2],
-    [PipelineInstance, 'pipeline_in_running_state', nil, 1, "running", nil, 0.0],
-    [PipelineInstance, 'has_component_with_completed_jobs', nil, 3, "complete", true, 1.0],
-    [PipelineInstance, 'pipeline_with_tagged_collection_input', "pwu", 1, "ready", nil, 0.0],
+    [Job, 'running_job_with_components', "jwu", 2, "Running", nil, 0.2],
+    [PipelineInstance, 'pipeline_in_running_state', nil, 1, "Running", nil, 0.0],
+    [PipelineInstance, 'has_component_with_completed_jobs', nil, 3, "Complete", true, 1.0],
+    [PipelineInstance, 'pipeline_with_tagged_collection_input', "pwu", 1, "Ready", nil, 0.0],
   ].each do |type, name, label, num_children, state, success, progress|
     test "children of #{name}" do
       use_token 'admin'

commit f3658ececac430166ee9766be1deee6a61153d0f
Author: radhika <radhika at curoverse.com>
Date:   Wed May 18 15:19:37 2016 -0400

    8876: add work_unit to workbench models

diff --git a/apps/workbench/app/models/job.rb b/apps/workbench/app/models/job.rb
index 6566aeb..b91c6bc 100644
--- a/apps/workbench/app/models/job.rb
+++ b/apps/workbench/app/models/job.rb
@@ -53,4 +53,8 @@ class Job < ArvadosBase
     stderr_log_query(limit).results.reverse.
       flat_map { |log| log.properties[:text].split("\n") rescue [] }
   end
+
+  def work_unit(label="")
+    JobWorkUnit.new(self, label)
+  end
 end
diff --git a/apps/workbench/app/models/job_task.rb b/apps/workbench/app/models/job_task.rb
index 15fc7fd..44d4d45 100644
--- a/apps/workbench/app/models/job_task.rb
+++ b/apps/workbench/app/models/job_task.rb
@@ -1,2 +1,5 @@
 class JobTask < ArvadosBase
+  def work_unit(label="")
+    JobTaskWorkUnit.new(self, label)
+  end
 end
diff --git a/apps/workbench/app/models/job_task_work_unit.rb b/apps/workbench/app/models/job_task_work_unit.rb
new file mode 100644
index 0000000..b4ad6f2
--- /dev/null
+++ b/apps/workbench/app/models/job_task_work_unit.rb
@@ -0,0 +1,2 @@
+class JobTaskWorkUnit < ProxyWorkUnit
+end
diff --git a/apps/workbench/app/models/job_work_unit.rb b/apps/workbench/app/models/job_work_unit.rb
new file mode 100644
index 0000000..2a5cb98
--- /dev/null
+++ b/apps/workbench/app/models/job_work_unit.rb
@@ -0,0 +1,51 @@
+class JobWorkUnit < ProxyWorkUnit
+  def children
+    # Job tasks
+    tasks = JobTask.filter([['job_uuid', '=', self.proxied.uuid]]).results
+    items = []
+    tasks.each do |t|
+      items << t.work_unit("task #{items.size}")
+    end
+
+    # Jobs submitted by this job  --  TBD
+
+    items
+  end
+
+  def progress
+    if self.proxied.state == 'Complete'
+      return 1.0
+    end
+
+    failed = self.proxied.tasks_summary[:failed] || 0 rescue 0
+    done = self.proxied.tasks_summary[:done] || 0 rescue 0
+    running = self.proxied.tasks_summary[:running] || 0 rescue 0
+    todo = self.proxied.tasks_summary[:todo] || 0 rescue 0
+    if done + running + failed + todo > 0
+      total_tasks = done + running + failed + todo
+      (done+failed).to_f / total_tasks
+    else
+      0.0
+    end
+  end
+
+  def docker_image
+    self.proxied[:docker_image_locator]
+  end
+
+  def nondeterministic
+    self.proxied[:nondeterministic]
+  end
+
+  def priority
+    self.proxied[:priority]
+  end
+
+  def log_collection
+    [self.proxied.log]
+  end
+
+  def output
+    self.proxied.output
+  end
+end
diff --git a/apps/workbench/app/models/pipeline_instance.rb b/apps/workbench/app/models/pipeline_instance.rb
index 6e556d5..f54b9f0 100644
--- a/apps/workbench/app/models/pipeline_instance.rb
+++ b/apps/workbench/app/models/pipeline_instance.rb
@@ -132,6 +132,10 @@ class PipelineInstance < ArvadosBase
     end
   end
 
+  def work_unit label
+    PipelineInstanceWorkUnit.new(self, label || self.name)
+  end
+
   private
 
   def components_map
diff --git a/apps/workbench/app/models/pipeline_instance_work_unit.rb b/apps/workbench/app/models/pipeline_instance_work_unit.rb
new file mode 100644
index 0000000..3f8c9a2
--- /dev/null
+++ b/apps/workbench/app/models/pipeline_instance_work_unit.rb
@@ -0,0 +1,55 @@
+class PipelineInstanceWorkUnit < ProxyWorkUnit
+  def children
+    items = []
+
+    jobs = {}
+    results = Job.where(uuid: self.proxied.job_ids.values).results
+    results.each do |j|
+      jobs[j.uuid] = j.work_unit("job #{items.size}")
+    end
+
+    components = self.proxied.components
+    components.each do |name, c|
+      if c.is_a?(Hash)
+        job = c[:job]
+        if job and job[:uuid] and jobs[job[:uuid]]
+          items << jobs[job[:uuid]]
+        else
+          items << ProxyWorkUnit.new(c, name)
+        end
+      end
+    end
+
+    items
+  end
+
+  def progress
+    if self.proxied.state == 'Complete'
+      return 1.0
+    end
+
+    done = 0
+    failed = 0
+    todo = 0
+    children.each do |c|
+      if c.success?.nil?
+        todo = todo+1
+      elsif c.success?
+        done = done+1
+      else
+        failed = failed+1
+      end
+    end
+
+    if done + failed + todo > 0
+      total = done + failed + todo
+      (done+failed).to_f / total
+    else
+      0.0
+    end
+  end
+
+  def log_collection
+    self.proxied.job_log_ids
+  end
+end
diff --git a/apps/workbench/app/models/proxy_work_unit.rb b/apps/workbench/app/models/proxy_work_unit.rb
new file mode 100644
index 0000000..502e6d2
--- /dev/null
+++ b/apps/workbench/app/models/proxy_work_unit.rb
@@ -0,0 +1,88 @@
+class ProxyWorkUnit < WorkUnit
+  attr_accessor :lbl
+  attr_accessor :proxied
+
+  def initialize proxied, label
+    self.lbl = label
+    self.proxied = proxied
+  end
+
+  def label
+    self.lbl
+  end
+
+  def uuid
+    self.proxied[:uuid]
+  end
+
+  def modified_by_user_uuid
+    self.proxied[:modified_by_user_uuid]
+  end
+
+  def created_at
+    self.proxied[:created_at]
+  end
+
+  def started_at
+    self.proxied[:started_at]
+  end
+
+  def finished_at
+    self.proxied[:finished_at]
+  end
+
+  def state_label
+    if ["Running", "RunningOnServer", "RunningOnClient"].include? self.proxied[:state].to_s
+      "running"
+    else
+      self.proxied[:state].to_s.downcase
+    end
+  end
+
+  def state_bootstrap_class
+    case self.proxied[:state]
+    when 'Complete'
+      'success'
+    when 'Failed', 'Cancelled'
+      'danger'
+    when 'Running', 'RunningOnServer', 'RunningOnClient'
+      'info'
+    else
+      'default'
+    end
+  end
+
+  def success?
+    if self.proxied[:state] == 'Complete'
+      true
+    elsif self.proxied[:state] == 'Failed'
+      false
+    else
+      nil
+    end
+  end
+
+  def parameters
+    self.proxied[:script_parameters]
+  end
+
+  def script
+    self.proxied[:script]
+  end
+
+  def script_repository
+    self.proxied[:repository]
+  end
+
+  def script_version
+    self.proxied[:script_version]
+  end
+
+  def supplied_script_version
+    self.proxied[:supplied_script_version]
+  end
+
+  def runtime_constraints
+    self.proxied[:runtime_constraints]
+  end
+end
diff --git a/apps/workbench/app/models/work_unit.rb b/apps/workbench/app/models/work_unit.rb
new file mode 100644
index 0000000..00f1435
--- /dev/null
+++ b/apps/workbench/app/models/work_unit.rb
@@ -0,0 +1,94 @@
+class WorkUnit
+  # This is just an abstract class that documents the WorkUnit interface; a
+  # class can implement the interface without being a subclass of WorkUnit.
+
+  def label
+    # returns the label that was assigned when creating the work unit
+  end
+
+  def uuid
+    # returns the arvados UUID of the underlying object
+  end
+
+  def children
+    # returns an array of child work units
+  end
+
+  def modified_by_user_uuid
+    # returns uuid of the user who modified this work unit most recently
+  end
+
+  def created_at
+    # returns created_at timestamp
+  end
+
+  def started_at
+    # returns started_at timestamp for this work unit
+  end
+
+  def finished_at
+    # returns finished_at timestamp
+  end
+
+  def state_label
+    # returns a string representing state of the work unit
+  end
+
+  def state_bootstrap_class
+    # returns a class like "danger", "success", or "warning" that a view can use directly to make a display class
+  end
+
+  def success?
+    # returnis true if the work unit finished successfully,
+    # false if it has a permanent failure,
+    # and nil if the final state is not determined.
+  end
+
+  def progress 
+    # returns a number between 0 and 1
+  end
+
+  def log_collection
+    # returns uuid or pdh with saved log data, if any
+  end
+
+  def parameters
+    # returns work unit parameters, if any
+  end
+
+  def script
+    # returns script for this work unit, if any
+  end
+
+  def script_repository
+    # returns this work unit's script_repository, if any
+  end
+
+  def script_version
+    # returns this work unit's script_version, if any
+  end
+
+  def supplied_script_version
+    # returns this work unit's supplied_script_version, if any
+  end
+
+  def docker_image
+    # returns this work unit's docker_image, if any
+  end
+
+  def runtime_constraints
+    # returns this work unit's runtime_constraints, if any
+  end
+
+  def priority
+    # returns this work unit's priority, if any
+  end
+
+  def nondeterministic
+    # returns if this is nondeterministic
+  end
+
+  def output
+    # returns uuid or pdh of output data, if any
+  end
+end
diff --git a/apps/workbench/test/unit/work_unit_test.rb b/apps/workbench/test/unit/work_unit_test.rb
new file mode 100644
index 0000000..66b4d9c
--- /dev/null
+++ b/apps/workbench/test/unit/work_unit_test.rb
@@ -0,0 +1,31 @@
+require 'test_helper'
+
+class WorkUnitTest < ActiveSupport::TestCase
+  [
+    [Job, 'running_job_with_components', "jwu", 2, "running", nil, 0.2],
+    [PipelineInstance, 'pipeline_in_running_state', nil, 1, "running", nil, 0.0],
+    [PipelineInstance, 'has_component_with_completed_jobs', nil, 3, "complete", true, 1.0],
+    [PipelineInstance, 'pipeline_with_tagged_collection_input', "pwu", 1, "ready", nil, 0.0],
+  ].each do |type, name, label, num_children, state, success, progress|
+    test "children of #{name}" do
+      use_token 'admin'
+      obj = find_fixture(type, name)
+      wu = obj.work_unit(label)
+
+      if label != nil
+        assert_equal(label, wu.label)
+      else
+        assert_equal(obj.name, wu.label)
+      end
+      assert_equal(obj['uuid'], wu.uuid)
+      assert_equal(state, wu.state_label)
+      assert_equal(success, wu.success?)
+      assert_equal(progress, wu.progress)
+
+      assert_equal(num_children, wu.children.size)
+      wu.children.each do |child|
+        assert_equal(true, child.respond_to?(:script))
+      end
+    end
+  end
+end
diff --git a/services/api/test/fixtures/job_tasks.yml b/services/api/test/fixtures/job_tasks.yml
new file mode 100644
index 0000000..4aded53
--- /dev/null
+++ b/services/api/test/fixtures/job_tasks.yml
@@ -0,0 +1,11 @@
+running_job_task_1:
+  uuid: zzzzz-ot0gb-runningjobtask1
+  owner_uuid: zzzzz-j7d0g-v955i6s2oi1cbso
+  created_at: <%= 3.minute.ago.to_s(:db) %>
+  job_uuid: zzzzz-8i9sb-with2components
+
+running_job_task_2:
+  uuid: zzzzz-ot0gb-runningjobtask2
+  owner_uuid: zzzzz-j7d0g-v955i6s2oi1cbso
+  created_at: <%= 3.minute.ago.to_s(:db) %>
+  job_uuid: zzzzz-8i9sb-with2components

-----------------------------------------------------------------------


hooks/post-receive
-- 




More information about the arvados-commits mailing list