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
end
def log_collection
- [self.proxied.log]
+ self.proxied.log
end
def output
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
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
0.0
end
end
-
- def log_collection
- self.proxied.job_log_ids
- end
end
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
self.proxied[:script]
end
- def script_repository
+ def repository
self.proxied[:repository]
end
def runtime_constraints
self.proxied[:runtime_constraints]
end
+
+ def children
+ []
+ end
end
# 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
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">
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 %>
--- /dev/null
+ <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>
--- /dev/null
+<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>
--- /dev/null
+<%# 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 %>
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'