pi
end
- helper_method :running_processes
- def running_processes lim
- lim = 8 if lim.nil?
+ helper_method :recent_processes
+ def recent_processes lim
+ lim = 12 if lim.nil?
- pipelines = PipelineInstance.limit(lim).order(["started_at desc", "created_at desc"]).filter([["state", "in", ["RunningOnServer", "RunningOnClient"]]])
+ pipelines = PipelineInstance.limit(lim).order(["created_at desc"])
- crs = ContainerRequest.order(["modified_at desc"]).filter([["requesting_container_uuid", "=", nil], ["state", "=", "Committed"]])
+ crs = ContainerRequest.limit(lim).order(["created_at desc"]).filter([["requesting_container_uuid", "=", nil]])
cr_uuids = crs.results.collect { |c| c.container_uuid }
- containers = Container.limit(lim).order(["started_at desc", "created_at desc"]).filter([["uuid", "in", cr_uuids], ["state", "=", "Running"]]).results if cr_uuids.any?
+ containers = Container.order(["created_at desc"]).results if cr_uuids.any?
procs = {}
- pipelines.results.each { |pi| procs[pi] = (pi.started_at || pi.created_at)}
+ pipelines.results.each { |pi| procs[pi] = pi.created_at }
containers.each { |c| procs[c] = c.created_at } if !containers.nil?
Hash[procs.sort_by {|key, value| value}].keys.reverse.first(lim)
end
- helper_method :finished_pipelines
- def finished_pipelines lim
- PipelineInstance.limit(lim).order(["finished_at desc"]).filter([["state", "in", ["Complete", "Failed", "Paused"]], ["finished_at", "!=", nil]])
- end
-
- helper_method :finished_processes
- def finished_processes lim
- lim = 8 if lim.nil?
-
- pipelines = PipelineInstance.limit(lim).order(["finished_at desc"]).filter([["state", "in", ["Complete", "Failed", "Paused"]], ["finished_at", "!=", nil]])
-
- crs = ContainerRequest.order(["modified_at desc"]).filter([["requesting_container_uuid", "=", nil], ["state", "=", "Final"]])
- cr_uuids = crs.results.collect { |c| c.container_uuid }
- containers = Container.limit(lim).order(["finished_at desc"]).filter([["uuid", "in", cr_uuids], ["state", "in", ["Complete", "Canceled"]], ["finished_at", "!=", nil]]).results if cr_uuids.any?
-
- procs = {}
- pipelines.results.each { |pi| procs[pi] = pi.finished_at }
- containers.each { |pi| procs[pi] = pi.finished_at } if !containers.nil?
-
- Hash[procs.sort_by {|key, value| value}].keys.reverse.first(lim)
- end
-
- helper_method :queued_processes
- def queued_processes
- procs = {}
- queued_jobs = Job.queue
- queued_jobs.each { |j| procs[j] = j.priority }
-
- queued_containers = Container.order(["priority desc", "created_at desc"]).filter([["state", "in", ["Queued", "Locked"]]])
- queued_containers.results.each { |c| procs[c] = c.priority }
-
- Hash[procs.sort_by {|key, value| value}].keys.reverse
- end
-
helper_method :recent_collections
def recent_collections lim
c = Collection.limit(lim).order(["modified_at desc"]).filter([["owner_uuid", "is_a", "arvados#group"]])
containers = Container.where(uuid: crs.keys).results
containers.each do |c|
- items << ContainerWorkUnit.new(c, crs[c.uuid])
+ items << c.work_unit(crs[c.uuid])
end
self.my_children = items
get(:log)
end
- def output
- get(:output)
+ def outputs
+ items = []
+ items << get(:output) if get(:output)
+ items
end
def uri
get(:log)
end
- def output
- get(:output)
+ def outputs
+ items = []
+ children.each do |c|
+ items.concat c.outputs
+ end
+ if !items.any?
+ items << get(:output) if get(:output)
+ end
+ items
end
def can_cancel?
@my_children = items
end
+ def outputs
+ items = []
+ components = get(:components)
+ components.each do |name, c|
+ if c.is_a?(Hash)
+ items << c[:output_uuid] if c[:output_uuid]
+ end
+ end
+ items
+ end
+
def uri
uuid = get(:uuid)
"/pipeline_instances/#{uuid}"
t
end
+ def modified_at
+ t = get(:modified_at)
+ t = Time.parse(t) if (t.andand.class == String)
+ t
+ end
+
def finished_at
t = get(:finished_at)
t = Time.parse(t) if (t.andand.class == String)
end
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 title
# returns created_at timestamp
end
+ def modified_at
+ # returns modified_at timestamp
+ end
+
def started_at
# returns started_at timestamp for this work unit
end
# returns if this is nondeterministic
end
- def output
- # returns uuid or pdh of output data, if any
- end
-
def outputs
- # returns array containing uuid or pdh of output data of all children
- # if no children, return output data if any
+ # returns array containing uuid or pdh of output data
end
def child_summary
-<h4>Queue</h4>
-<% queue = queued_processes %>
-<% if queue.any? %>
-
-<% queue.each do |q| %>
- <% wu = q.work_unit %>
- <div class="row">
- <div class="col-md-3 text-overflow-ellipsis">
- <%= link_to_if_arvados_object q, friendly_name: true %>
- </div>
- <div class="col-md-4">
- <%= render_localized_date(wu.created_at) %>
- </div>
- <div class="col-md-3">
- <%= render_runtime(Time.now - wu.created_at, false) %>
- </div>
- <div class="col-md-2">
- <%= wu.priority %>
- </div>
- </div>
-<% end %>
- <div class="row">
- <div class="col-md-3">
- <b>Process</b>
- </div>
- <div class="col-md-4">
- <b>Submitted</b>
- </div>
- <div class="col-md-3">
- <b>Queued</b>
- </div>
- <div class="col-md-2">
- <b>Priority</b>
- </div>
- </div>
-<% else %>
- There are currently no processes in your queue.
-<% end %>
-
<h4>Node status</h4>
+<% active_nodes = 0 %>
<div class="compute-summary-nodelist">
<% nodes.sort_by { |n| n.hostname || "" }.each do |n| %>
<% if n.crunch_worker_state.in? ["busy", "idle"] and (Time.now - n[:last_ping_at]) < 3600 %>
+ <% active_nodes += 1 %>
<div class="compute-summary">
<a data-toggle="collapse" href="#detail_<%= n.hostname %>" class="compute-summary-head label label-<%= if n.crunch_worker_state == 'busy' then 'primary' else 'default' end %>">
<%= n.hostname %>
</div>
<% end %>
<% end %>
+ <% if active_nodes == 0 %>
+ No active nodes
+ <% end %>
</div>
<div class="row">
<div class="col-md-6">
<div class="panel panel-default" style="min-height: 10.5em">
- <div class="panel-heading"><span class="panel-title">Active processes</span>
+ <div class="panel-heading"><span class="panel-title">Recent processes</span>
<% if current_user.andand.is_active %>
- <span class="pull-right">
- <%= link_to(
- choose_pipeline_templates_path(
- title: 'Choose a pipeline to run:',
- action_name: 'Next: choose inputs <i class="fa fa-fw fa-arrow-circle-right"></i>',
- action_href: pipeline_instances_path,
- action_method: 'post',
- action_data: {'selection_param' => 'pipeline_instance[pipeline_template_uuid]', 'pipeline_instance[owner_uuid]' => current_user.uuid, 'success' => 'redirect-to-created-object'}.to_json),
- { class: "btn btn-primary btn-xs", remote: true }) do %>
- <i class="fa fa-fw fa-gear"></i> Run a pipeline...
- <% end %>
- </span>
- <% end %>
- </div>
-
- <% _running_processes = running_processes(8) %>
- <% _finished_processes = finished_processes(8) %>
- <div class="panel-body active-processes">
- <% if _running_processes.empty? %>
- No processes are currently running.
- <% else %>
- <% _running_processes.each do |p| %>
- <% wu = p.work_unit %>
- <div class="dashboard-panel-info-row">
- <div class="clearfix">
- <%= link_to_if_arvados_object p, {friendly_name: true} %>
- <div class="pull-right" style="width: 40%">
- <div class="progress" style="margin-bottom: 0px">
- <% wu.progress %>
- </div>
- </div>
- </div>
-
- <%
- children = wu.children
- running = children.select { |c| c.state_label == "Running" }
- queued = children.select { |c| c.state_label == "Queued" }
- %>
-
- <div class="clearfix">
- Started at <%= render_localized_date(wu.started_at || wu.created_at, "noseconds") %>.
- <% wu_time = Time.now - (wu.started_at || wu.created_at) %>
- Active for <%= render_runtime(wu_time, false) %>.
-
- <div class="pull-right">
- <% running.each do |r| %>
- <span class="label label-<%= r.state_bootstrap_class %>"> <%= r.label || r.state_label || 'Not ready' %> </span>
- <% end %>
- <% queued.each do |q| %>
- <span class="label label-<%= q.state_bootstrap_class %>"> <%= q.label || r.state_label || 'Not ready' %> </span>
+ <span class="pull-right">
+ <span>
+ <%= link_to(
+ choose_pipeline_templates_path(
+ title: 'Choose a pipeline to run:',
+ action_name: 'Next: choose inputs <i class="fa fa-fw fa-arrow-circle-right"></i>',
+ action_href: pipeline_instances_path,
+ action_method: 'post',
+ action_data: {'selection_param' => 'pipeline_instance[pipeline_template_uuid]', 'pipeline_instance[owner_uuid]' => current_user.uuid, 'success' => 'redirect-to-created-object'}.to_json),
+ { class: "btn btn-primary btn-xs", remote: true }) do %>
+ <i class="fa fa-fw fa-gear"></i> Run a pipeline...
+ <% end %>
+ </span>
+ <span>
+ <%= link_to pipeline_instances_path, class: 'btn btn-default btn-xs' do %>
+ All pipelines <i class="fa fa-fw fa-arrow-circle-right"></i>
<% end %>
- </div>
- </div>
- </div>
- <% end %>
+ </span>
+ </span>
<% end %>
</div>
- </div>
- <div class="panel panel-default">
- <div class="panel-heading"><span class="panel-title">Recently finished processes</span>
- <span class="pull-right">
- <%= link_to pipeline_instances_path, class: 'btn btn-default btn-xs' do %>
- All pipelines <i class="fa fa-fw fa-arrow-circle-right"></i>
- <% end %>
- </span>
- </div>
- <div class="panel-body finished-processes">
- <% _finished_processes.each do |p| %>
+ <% _recent_processes = recent_processes(12) %>
+ <div class="panel-body recent-processes">
+ <% if _recent_processes.empty? %>
+ No recent processes.
+ <% else %>
+ <% _recent_processes.each do |p| %>
<% wu = p.work_unit %>
+ <% if wu.is_finished? %>
<div class="dashboard-panel-info-row">
<div class="row">
<div class="col-md-6 text-overflow-ellipsis">
<% elsif outputs.size == 1 %>
<i class="fa fa-fw fa-archive"></i> <%= link_to_if_arvados_object outputs[0], friendly_name: true %>
<% else %>
- <a href="#<%= wu.uuid %>-outputs" data-toggle="collapse">Outputs <span class="caret"></span></a>
+ <%= render partial: 'work_unit/show_outputs', locals: {id: wu.uuid, outputs: outputs, align:"pull-right"} %>
<% end %>
</span>
</div>
</div>
- <div class="row collapse" id="<%= wu.uuid %>-outputs" >
- <div class="col-md-12">
- <div class="pull-right" style="max-width: 100%">
- <% outputs.each do |out| %>
- <div class="text-overflow-ellipsis">
- <i class="fa fa-fw fa-archive"></i> <%= link_to_if_arvados_object out, friendly_name: true %>
- </div>
- <% end %>
+ </div>
+ <% else %>
+ <div class="dashboard-panel-info-row">
+ <div class="clearfix">
+ <%= link_to_if_arvados_object p, {friendly_name: true} %>
+ <div class="pull-right" style="width: 40%">
+ <div class="progress" style="margin-bottom: 0px">
+ <% wu.progress %>
</div>
</div>
</div>
+
+ <%
+ children = wu.children
+ running = children.select { |c| c.state_label == "Running" }
+ queued = children.select { |c| c.state_label == "Queued" }
+ %>
+
+ <div class="clearfix">
+ Started at <%= render_localized_date(wu.started_at || wu.created_at, "noseconds") %>.
+ <% wu_time = Time.now - (wu.started_at || wu.created_at) %>
+ Active for <%= render_runtime(wu_time, false) %>.
+
+ <div class="pull-right">
+ <% running.each do |r| %>
+ <span class="label label-<%= r.state_bootstrap_class %>"> <%= r.label || r.state_label || 'Not ready' %> </span>
+ <% end %>
+ <% queued.each do |q| %>
+ <span class="label label-<%= q.state_bootstrap_class %>"> <%= q.label || r.state_label || 'Not ready' %> </span>
+ <% end %>
+ </div>
+ </div>
</div>
+ <% end %>
+ <% end %>
<% end %>
</div>
</div>
<div class="col-md-6">
<% nodes = Node.all %>
<div class="panel panel-default" style="min-height: 10.5em">
- <div class="panel-heading"><span class="panel-title">Compute and job status</span>
+ <div class="panel-heading"><span class="panel-title">Compute node status</span>
<span class="pull-right">
- <%= link_to jobs_path, class: 'btn btn-default btn-xs' do %>
- All jobs <i class="fa fa-fw fa-arrow-circle-right"></i>
+ <% if current_user.andand.is_admin %>
+ <span>
+ <%= link_to nodes_path, class: 'btn btn-default btn-xs' do %>
+ All nodes <i class="fa fa-fw fa-arrow-circle-right"></i>
+ <% end %>
+ </span>
<% end %>
+ <span>
+ <%= link_to jobs_path, class: 'btn btn-default btn-xs' do %>
+ All jobs <i class="fa fa-fw fa-arrow-circle-right"></i>
+ <% end %>
+ </span>
</span>
</div>
<div class="panel-body compute-node-summary-pane">
No <%= current_obj.title %> has been submitted yet.
<% else %>
<table>
- <% [:uuid, :modified_by_user_uuid, :created_at, :started_at, :finished_at, :output, :priority].each do |k| %>
+ <% keys = [:uuid, :modified_by_user_uuid, :created_at, :started_at, :finished_at, :priority] %>
+ <% keys << :outputs if @object.uuid == current_obj.uuid %>
+ <% keys.each do |k| %>
<% val = current_obj.send(k) if current_obj.respond_to?(k) %>
<% if val %>
<tr>
<%= link_to_arvados_object_if_readable(val, val, friendly_name: true) %>
<% elsif k.to_s.end_with? '_at' %>
<%= render_localized_date(val) %>
- <% elsif k == :output %>
- <%= link_to_arvados_object_if_readable(val, 'Output data not available', friendly_name: true) %>
+ <% elsif k == :outputs and val.any? %>
+ <% if val.size == 1 %>
+ <%= link_to_arvados_object_if_readable(val[0], 'Output data not available', friendly_name: true) %>
+ <% else %>
+ <%= render partial: 'work_unit/show_outputs', locals: {id: current_obj.uuid, outputs: val, align:""} %>
+ <% end %>
<% else %>
<%= val %>
<% end %>
</div>
<% elsif current_obj.is_finished? %>
<div class="col-md-3 text-overflow-ellipsis">
- <% if current_obj.output %>
- <%= link_to_arvados_object_if_readable(current_obj.output, 'Output data not available', link_text: "Output of #{current_obj.label}") %>
+ <% outputs = current_obj.outputs %>
+ <% if outputs.any? %>
+ <% if outputs.size == 1 %>
+ <%= link_to_arvados_object_if_readable(outputs[0], 'Output data not available', link_text: "Output of #{current_obj.label}") %>
+ <% else %>
+ <%= render partial: 'work_unit/show_outputs', locals: {id: current_obj.uuid, outputs: outputs, align:"pull-right"} %>
+ <% end %>
<% else %>
No output.
<% end %>
preload_objects_for_dataclass resource_class, uuids
end
- collections = wu.children.collect {|j| j.output}.compact
+ collections = wu.children.collect {|j| j.outputs}.compact
+ collections = collections.flatten.uniq
collections.concat wu.children.collect {|j| j.docker_image}.uniq.compact
collections_pdhs = collections.select {|x| !(m = CollectionsHelper.match(x)).nil?}.uniq.compact
collections_uuids = collections - collections_pdhs
--- /dev/null
+<span class="<%=align%>"><a href="#<%= id %>-outputs" data-toggle="collapse">Outputs <span class="caret"></span></a></span>
+<div class="row collapse" id="<%= id %>-outputs" >
+ <div class="col-md-12">
+ <div class="pull-right" style="max-width: 100%">
+ <% outputs.each do |out| %>
+ <div class="text-overflow-ellipsis">
+ <i class="fa fa-fw fa-archive"></i> <%= link_to_if_arvados_object out, friendly_name: true %>
+ </div>
+ <% end %>
+ </div>
+ </div>
+</div>
first('button', text: 'x').click
end
- assert_text 'Active processes' # seeing dashboard now
+ assert_text 'Recent processes' # seeing dashboard now
end
end
end
end
- test "dashboard panes" do
- visit page_with_token('active')
+ [
+ ['active', false],
+ ['admin', true],
+ ].each do |token, is_admin|
+ test "visit dashboard as #{token}" do
+ visit page_with_token(token)
- assert_text 'Active processes' # seeing dashboard now
- within('.active-processes') do
- assert_text 'zzzzz-dz642-runningcontainr'
- assert_text 'zzzzz-dz642-runningcontain2'
- assert_text 'zzzzz-d1hrv-partdonepipelin'
- assert_no_text 'zzzzz-d1hrv-twodonepipeline'
- assert_no_text 'zzzzz-xvhdp-cr4queuedcontnr'
- end
- within('.finished-processes') do
- assert_text 'zzzzz-d1hrv-twodonepipeline'
- assert_text 'zzzzz-dz642-compltcontainer'
- assert_text 'zzzzz-dz642-compltcontainr2'
- assert_no_text 'zzzzz-d1hrv-partdonepipelin'
- assert_no_text 'zzzzz-dz642-runningcontainr'
- end
+ assert_text 'Recent processes' # seeing dashboard now
+ within('.recent-processes') do
+ page.has_button? 'Run a pipeline'
+ page.has_link? 'All pipelines'
+ assert_text 'zzzzz-d1hrv-partdonepipelin'
+ assert_text 'zzzzz-d1hrv-twodonepipeline'
+ assert_text 'zzzzz-dz642-runningcontainr'
+ assert_text 'zzzzz-dz642-runningcontain2'
+ end
- within('.compute-node-summary-pane') do
- click_link 'Details'
- assert_text 'zzzzz-dz642-lockedcontainer'
- assert_text 'zzzzz-dz642-queuedcontainer'
- assert_text '"foo" job submitted'
+ within('.compute-node-summary-pane') do
+ page.has_link?('All nodes') if is_admin
+ page.has_link? 'All jobs'
+ click_link 'Details'
+ assert_text 'compute0'
+ end
end
end
end
test "login with api_token works after redirect" do
visit page_with_token('active_trustedclient')
- assert page.has_text?('Active processes'), "Missing 'Active processes' from page"
+ assert page.has_text?('Recent processes'), "Missing 'Recent processes' from page"
assert_no_match(/\bapi_token=/, current_path)
end
assert page.has_text? 'Textile description for pipeline template'
assert page.has_link? 'Go to dashboard'
click_link 'Go to dashboard'
- assert page.has_text? 'Active processes'
+ assert page.has_text? 'Recent processes'
# again visit recent templates page and verify edited description
visit page_with_token("active", "/pipeline_templates")
assert page.has_text?('Save profile'), 'No text - Save profile'
add_profile user
else
- assert page.has_text?('Active processes'), 'Not found text - Active processes'
+ assert page.has_text?('Recent processes'), 'Not found text - Recent processes'
assert page.has_no_text?('Save profile'), 'Found text - Save profile'
end
elsif invited
end
# profile saved and in home page now
- assert page.has_text?('Active processes'), 'No text - Active processes'
+ assert page.has_text?('Recent processes'), 'No text - Recent processes'
end
[
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
state: Running
priority: 1
- created_at: 2016-01-11 11:11:11.111111111 Z
- updated_at: 2016-01-11 11:11:11.111111111 Z
- started_at: 2016-01-11 11:11:11.111111111 Z
+ created_at: <%= 1.minute.ago.to_s(:db) %>
+ updated_at: <%= 1.minute.ago.to_s(:db) %>
+ started_at: <%= 1.minute.ago.to_s(:db) %>
container_image: test
cwd: test
output: test
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
state: Running
priority: 1
- created_at: 2016-01-11 11:11:11.111111111 Z
- updated_at: 2016-01-11 11:11:11.111111111 Z
- started_at: 2016-01-12 11:11:11.111111111 Z
+ created_at: <%= 2.minute.ago.to_s(:db) %>
+ updated_at: <%= 2.minute.ago.to_s(:db) %>
+ started_at: <%= 2.minute.ago.to_s(:db) %>
container_image: test
cwd: test
output: test
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
state: Locked
priority: 2
- created_at: 2016-01-01 11:11:11.111111111 Z
- updated_at: 2016-01-01 11:11:11.111111111 Z
+ created_at: <%= 2.minute.ago.to_s(:db) %>
+ updated_at: <%= 2.minute.ago.to_s(:db) %>
container_image: test
cwd: test
output: test