From 7f5a540ea4b1bad1a7b1646543e0cd48ff2af7ba Mon Sep 17 00:00:00 2001 From: radhika Date: Fri, 20 May 2016 23:40:00 -0400 Subject: [PATCH] 8876: work_unit views in progress --- .../app/helpers/pipeline_instances_helper.rb | 4 +- apps/workbench/app/models/job_work_unit.rb | 2 +- .../app/models/pipeline_instance_work_unit.rb | 8 +- apps/workbench/app/models/proxy_work_unit.rb | 10 +- apps/workbench/app/models/work_unit.rb | 4 +- .../app/views/jobs/_show_status.html.erb | 3 +- .../_show_components.html.erb | 2 +- .../work_unit/_component_detail.html.erb | 91 +++++++++++++++ .../app/views/work_unit/_show_child.html.erb | 103 +++++++++++++++++ .../views/work_unit/_show_component.html.erb | 105 ++++++++++++++++++ apps/workbench/test/unit/work_unit_test.rb | 8 +- 11 files changed, 319 insertions(+), 21 deletions(-) create mode 100644 apps/workbench/app/views/work_unit/_component_detail.html.erb create mode 100644 apps/workbench/app/views/work_unit/_show_child.html.erb create mode 100644 apps/workbench/app/views/work_unit/_show_component.html.erb diff --git a/apps/workbench/app/helpers/pipeline_instances_helper.rb b/apps/workbench/app/helpers/pipeline_instances_helper.rb index 8fafbc2022..b2486c1d90 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 2a5cb98810..8246e8ac87 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 3f8c9a2baa..94990eee16 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 502e6d250c..e7806783eb 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 00f1435de5..41855199c8 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 807520940c..8d54b20cfd 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")}) %>
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 dae57aa0e8..4196558b3c 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(' ') %>" >
- <%= 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 0000000000..045154a220 --- /dev/null +++ b/apps/workbench/app/views/work_unit/_component_detail.html.erb @@ -0,0 +1,91 @@ +
+
+
+ + <% [: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? %> + + + + + <% end %> + <% end %> +
+ <%= k.to_s %>: + + <% 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 %> +
+
+
+ + <% # 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? %> + + + + + <% end %> + <% end %> + <% if current_obj.runtime_constraints.andand[:docker_image] and current_obj.docker_image %> + + + + + + + + + <% end %> +
+ <%= k.to_s %>: + + <% 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 %> +
+ docker_image: + + <%= current_obj.runtime_constraints[:docker_image] %> +
+ docker_image_locator: + + <%= link_to_arvados_object_if_readable(current_obj.docker_image, + current_obj.docker_image, friendly_name: true) %> +
+
+
+ <% unless current_obj.parameters.nil? %> +
+
+

script_parameters:

+
<%= JSON.pretty_generate(current_obj.parameters) rescue nil %>
+
+
+ <% end %> +
+ 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 0000000000..10c6ac08ee --- /dev/null +++ b/apps/workbench/app/views/work_unit/_show_child.html.erb @@ -0,0 +1,103 @@ +
+
+
+
+ <%# column offset 0 %> + + + <%# column offset 2 %> +
+ <%= current_obj.progress %> +
+ + <%# column offset 4 %> + <% if not current_obj %> +
+ <% else %> +
+ <% 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 %> +
+ + <%# column offset 5 %> + <% if current_obj.state_label != "Queued" %> +
+ <% 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 %> +
+ <% end %> + + <% if current_obj.state_label == "Queued" %> + <%# column offset 5 %> +
+ <% queuetime = Time.now - Time.parse(current_obj.created_at.to_s) %> + Queued for <%= render_runtime(queuetime, false) %>. +
+ <% elsif current_obj.state_label == "Running" %> + <%# column offset 8 %> +
+ + <%= 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 + +
+ <% elsif current_obj.state_label.in? ["Complete", "Failed", "Cancelled"] %> + <%# column offset 8 %> +
+ <% 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 %> +
+ <% end %> + + <% if current_obj.state_label.in? ["Queued", "Running"] and @object.editable? %> + <%# column offset 11 %> +
+ <%= 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 %> +
+ <% end %> + <% end %> +
+
+
+ +
+
+ <%= render partial: 'work_unit/show_component', locals: {wu: current_obj} %> +
+
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 0000000000..0e650acd4c --- /dev/null +++ b/apps/workbench/app/views/work_unit/_show_component.html.erb @@ -0,0 +1,105 @@ +<%# Work unit status %> + +
+ Current state: + <% if wu.state_label == "running" %> + Active + <% else %> + <%= wu.state_label %> + <% end %> +   +
+ +<% if wu.state_label == 'Paused' %> +

+ This work unit is paused. Work unit children that are + already running will continue to run, but no new work units will be submitted. +

+<% end %> + +<% runningtime = determine_wallclock_runtime(wu.children) %> + +

+ <% 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 %> +

+ +

+ 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 %> +

+ +

+ <%= render partial: 'work_unit/component_detail', locals: {current_obj: wu} %> +

+ +<%# 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 66b4d9cd73..63f6a5aacd 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' -- 2.30.2