[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