[ARVADOS] created: aadca3ff41a12a7a52a2a072696564b90537b9b3

git at public.curoverse.com git at public.curoverse.com
Wed Sep 10 17:12:28 EDT 2014


        at  aadca3ff41a12a7a52a2a072696564b90537b9b3 (commit)


commit aadca3ff41a12a7a52a2a072696564b90537b9b3
Author: Peter Amstutz <peter.amstutz at curoverse.com>
Date:   Wed Sep 10 17:12:09 2014 -0400

    3187: Lots of work on presentation of job details, calculating time and
    concurrency factors.

diff --git a/apps/workbench/app/controllers/jobs_controller.rb b/apps/workbench/app/controllers/jobs_controller.rb
index b3204bf..40f4378 100644
--- a/apps/workbench/app/controllers/jobs_controller.rb
+++ b/apps/workbench/app/controllers/jobs_controller.rb
@@ -36,7 +36,11 @@ class JobsController < ApplicationController
 
   def cancel
     @object.cancel
-    redirect_to @object
+    if params[:return_to]
+      redirect_to params[:return_to]
+    else
+      redirect_to @object
+    end
   end
 
   def show
diff --git a/apps/workbench/app/controllers/pipeline_instances_controller.rb b/apps/workbench/app/controllers/pipeline_instances_controller.rb
index 9b31912..72af56a 100644
--- a/apps/workbench/app/controllers/pipeline_instances_controller.rb
+++ b/apps/workbench/app/controllers/pipeline_instances_controller.rb
@@ -5,7 +5,40 @@ class PipelineInstancesController < ApplicationController
   include PipelineComponentsHelper
 
   def copy
-    @object = @object.dup
+    template = PipelineTemplate.find?(@object.pipeline_template_uuid)
+
+    source = @object
+    @object = PipelineInstance.new
+    @object.pipeline_template_uuid = source.pipeline_template_uuid
+
+    if params['components'] == 'use_latest' and template
+      @object.components = template.components.deep_dup
+      @object.components.each do |cname, component|
+        # Go through the script parameters of each component
+        # that are marked as user input and copy them over.
+        component[:script_parameters].each do |pname, val|
+          if val.is_a? Hash and val[:dataclass]
+            # this is user-inputtable, so check the value from the source pipeline
+            srcvalue = source.components[cname][:script_parameters][pname]
+            if not srcvalue.nil?
+              component[:script_parameters][pname] = srcvalue
+            end
+          end
+        end
+      end
+    else
+      @object.components = source.components.deep_dup
+    end
+
+    if params['script'] == 'use_same'
+      # Go through each component and copy the script_version from each job.
+      @object.components.each do |cname, component|
+        if source.components['cname'][:job]
+          component.script_version = source.components[cname][:job].script_version
+        end
+      end
+    end
+
     @object.components.each do |cname, component|
       component.delete :job
     end
diff --git a/apps/workbench/app/helpers/jobs_helper.rb b/apps/workbench/app/helpers/jobs_helper.rb
index 60268cb..06c3d0d 100644
--- a/apps/workbench/app/helpers/jobs_helper.rb
+++ b/apps/workbench/app/helpers/jobs_helper.rb
@@ -18,4 +18,5 @@ module JobsHelper
     end
     return results
   end
+
 end
diff --git a/apps/workbench/app/helpers/pipeline_components_helper.rb b/apps/workbench/app/helpers/pipeline_components_helper.rb
index 7584011..28adfa9 100644
--- a/apps/workbench/app/helpers/pipeline_components_helper.rb
+++ b/apps/workbench/app/helpers/pipeline_components_helper.rb
@@ -4,6 +4,7 @@ module PipelineComponentsHelper
       render(partial: "pipeline_instances/show_components_#{template_suffix}",
              locals: locals)
     rescue Exception => e
+      logger.error "#{e.inspect}"
       logger.error "#{e.backtrace.join("\n\t")}"
       case fallback
       when :json
diff --git a/apps/workbench/app/helpers/pipeline_instances_helper.rb b/apps/workbench/app/helpers/pipeline_instances_helper.rb
index b6df82f..d2b3a85 100644
--- a/apps/workbench/app/helpers/pipeline_instances_helper.rb
+++ b/apps/workbench/app/helpers/pipeline_instances_helper.rb
@@ -94,10 +94,13 @@ module PipelineInstancesHelper
         pj[:result] = 'none'
         pj[:labeltype] = 'default'
       end
+
       pj[:job_id] = pj[:job][:uuid]
       pj[:script] = pj[:job][:script] || c[:script]
+      pj[:repository] = pj[:job][:script] || c[:repository]
       pj[:script_parameters] = pj[:job][:script_parameters] || c[:script_parameters]
       pj[:script_version] = pj[:job][:script_version] || c[:script_version]
+      pj[:nondeterministic] = pj[:job][:nondeterministic] || c[:nondeterministic]
       pj[:output] = pj[:job][:output]
       pj[:output_uuid] = c[:output_uuid]
       pj[:finished_at] = (Time.parse(pj[:job][:finished_at]) rescue nil)
@@ -153,4 +156,33 @@ module PipelineInstancesHelper
     end
     ret
   end
+
+  def runtime duration, long
+    hours = 0
+    minutes = 0
+    seconds = 0
+    if duration >= 3600
+      hours = (duration / 3600).floor
+      duration -= hours * 3600
+    end
+    if duration >= 60
+      minutes = (duration / 60).floor
+      duration -= minutes * 60
+    end
+    duration = duration.floor
+
+    if long
+      s = ""
+      if hours > 0 then
+        s += "#{hours} hour#{'s' if hours != 1} "
+      end
+      if minutes > 0 then
+        s += "#{minutes} minute#{'s' if minutes != 1} "
+      end
+      s += "#{duration} second#{'s' if duration != 1}"
+    else
+      s = "#{hours}:#{minutes.to_s.rjust(2, '0')}:#{duration.to_s.rjust(2, '0')}"
+    end
+    s
+  end
 end
diff --git a/apps/workbench/app/models/job.rb b/apps/workbench/app/models/job.rb
index aac6168..309cade 100644
--- a/apps/workbench/app/models/job.rb
+++ b/apps/workbench/app/models/job.rb
@@ -33,4 +33,25 @@ class Job < ArvadosBase
   def cancel
     arvados_api_client.api "jobs/#{self.uuid}/", "cancel", {}
   end
+
+  def state
+    Job::state(self)
+  end
+
+  def self.state job
+    if not job[:cancelled_at].nil?
+      "Canceled"
+    elsif not job[:finished_at].nil? or not job[:success].nil?
+      if job[:success]
+        "Completed"
+      else
+        "Failed"
+      end
+    elsif job[:running]
+      "Running"
+    else
+      "Queued"
+    end
+  end
+
 end
diff --git a/apps/workbench/app/views/application/_job_status_label.html.erb b/apps/workbench/app/views/application/_job_status_label.html.erb
index ae00e3a..c6ab8e4 100644
--- a/apps/workbench/app/views/application/_job_status_label.html.erb
+++ b/apps/workbench/app/views/application/_job_status_label.html.erb
@@ -1,13 +1,11 @@
-<% if j[:success] %>
-  <span class="label label-success"><%= if defined? title then title else 'success' end %></span>
-<% elsif j[:success] == false %>
-  <span class="label label-danger"><%= if defined? title then title else 'failed' end %></span>
-<% elsif j[:finished_at] %>
-  <span class="label label-default"><%= if defined? title then title else 'finished' end %></span>
-<% elsif j[:started_at] %>
-  <span class="label label-info"><%= if defined? title then title else 'running' end %></span>
-<% elsif not j.nil? %>
-  <span class="label label-default"><%= if defined? title then title else 'queued' end %></span>
-<% else %>
-  <span class="label label-default"><%= if defined? title then title else 'not ready' end %></span>
-<% end %>
+<% status = Job.state j %>
+<% to_label = {
+     "Canceled" => "danger",
+     "Completed" => "success",
+     "Running" => "info",
+     "Failed" => "danger",
+     "Queued" => "default",
+     nil => "default"
+   } %>
+
+  <span class="label label-<%= to_label[status] %>"><%= if defined? title then title else status.downcase end %></span>
diff --git a/apps/workbench/app/views/application/_show_advanced.html.erb b/apps/workbench/app/views/application/_show_advanced.html.erb
index e8474f6..70dd96b 100644
--- a/apps/workbench/app/views/application/_show_advanced.html.erb
+++ b/apps/workbench/app/views/application/_show_advanced.html.erb
@@ -1,9 +1,9 @@
 <div class="panel-group" id="arv-adv-accordion">
-  <% ['Metadata',
-     'API response',
-     'Python example',
-     'CLI example',
-     'curl example'].each do |section| %>
+  <% ['API response',
+      'Metadata',
+      'Python example',
+      'CLI example',
+      'curl example'].each do |section| %>
     <% section_id = section.gsub(" ","_").downcase %>
     <div class="panel panel-default">
       <div class="panel-heading">
@@ -13,7 +13,7 @@
           </a>
         </h4>
       </div>
-      <div id="advanced_<%=section_id%>" class="panel-collapse collapse">
+      <div id="advanced_<%=section_id%>" class="panel-collapse collapse <%#= 'in' if section == 'API response'%>">
         <div class="panel-body">
           <%= render partial: "show_advanced_#{section_id}", locals: {object: @object} %>
         </div>
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 786a8fd..649a119 100644
--- a/apps/workbench/app/views/pipeline_instances/_show_components.html.erb
+++ b/apps/workbench/app/views/pipeline_instances/_show_components.html.erb
@@ -1,7 +1,13 @@
 <% if !@object.state.in? ['New', 'Ready'] %>
 
   <div class="pull-right">
-    Current state: <span class="badge badge-info" data-pipeline-state="<%= @object.state %>"><%= @object.state.sub('OnServer', '') %></span> 
+    Current state: <span class="badge badge-info" data-pipeline-state="<%= @object.state %>">
+      <% if @object.state == "RunningOnServer" %>
+        Active
+      <% else %>
+        <%= @object.state %>
+      <% end %>
+    </span> 
   </div>
 
   <%= render_pipeline_components("running", :json) %>
diff --git a/apps/workbench/app/views/pipeline_instances/_show_components_running.html.erb b/apps/workbench/app/views/pipeline_instances/_show_components_running.html.erb
index 9f46e3d..8fb263c 100644
--- a/apps/workbench/app/views/pipeline_instances/_show_components_running.html.erb
+++ b/apps/workbench/app/views/pipeline_instances/_show_components_running.html.erb
@@ -1,66 +1,227 @@
-  <table class="table pipeline-components-table">
-    <colgroup>
-      <col style="width: 15%" />
-      <col style="width: 25%" />
-      <col style="width: 8%" />
-      <col style="width: 13%" />
-      <col style="width: 12%" />
-      <col style="width: 14%" />
-      <col style="width: 13%" />
-    </colgroup>
-    <thead>
-      <tr>
-        <th colspan="2">
-          component
-        </th><th colspan="5">
-          job
-          <%# format:'js' here helps browsers avoid using the cached js
-          content in html context (e.g., duplicate tab -> see
-          javascript) %>
-          <%= link_to '(refresh)', {format: :js}, {class: 'refresh hide', remote: true, method: 'get'} %>
-        </th>
-      </tr>
-    </thead>
-    <tbody>
-      <% render_pipeline_jobs.each do |pj| %>
-        <tr data-object-uuid="<%= pj[:job].andand[:uuid] %>">
-          <td>
-            <%= pj[:name] %>
-          </td><td>
-            <%= pj[:script] %>
-            <br /><span class="deemphasize"><%= pj[:script_version] %></span>
-          </td><td>
-            <%= render(partial: 'job_status_label', locals: { j: pj[:job] }) %>
-          </td><td>
-            <%= pj[:progress_bar] %>
-          </td>
-          <% current_job = pj[:job] rescue nil %>
-          <td>
-            <% if current_job.is_a? Job %>
-              <%= render partial: 'show_object_button', locals: {object: current_job, size: 'xs', link_text: 'Show job details'} %>
-            <% end %>
-          </td><td>
-            <% if current_job.andand[:log] %>
-              <% fixup = /([a-f0-9]{32}\+\d+)(\+?.*)/.match(current_job[:log])%>
-              <% Collection.limit(1).where(portable_data_hash: fixup[1]).each do |c| %>
-                <% c.files.first.andand do |file| %>
-                  <%= link_to url_for(controller: 'collections', action: 'show_file', uuid: current_job[:log], file: "#{file[0]}/#{file[1]}", disposition: 'inline', size: file[2]), class: 'btn btn-default btn-xs' do %>
-                    <i class="fa fa-fw fa-info"></i> Show log messages
-                  <% end %>
-                <% end %>
+<%# Summary %>
+
+<% if @object.state == 'Paused' %>
+  <p>
+    This pipeline is paused.  Jobs that are
+    already running will continue to run, but no new jobs will be submitted.
+  </p>
+<% end %>
+
+<p>
+  This pipeline
+  <% if @object.state == 'Complete' %>
+    completed in
+  <% elsif @object.state == 'Failed' %>
+    failed after
+  <% else %>
+    has been active for
+  <% end %>
+  <% walltime = if @object.started_at
+        if @object.finished_at
+          @object.finished_at - @object.started_at
+        else
+          Time.now - @object.started_at
+        end
+      else
+        0
+      end
+      %>
+  <%= runtime(walltime, true) %>, running for
+
+    <% tasks = JobTask.filter([['job_uuid', 'in', render_pipeline_jobs.map { |j| j[:job].andand[:uuid] }]]).results %>
+
+    <%# want to buy: algorithm that calculates wall clock runtime that takes into account
+        concurrent jobs.  %>
+    <% runningtime = render_pipeline_jobs.map { |j|
+         if j[:job] and j[:job].started_at
+           (if j[:job].finished_at then j[:job].finished_at else Time.now() end) - j[:job].started_at
+         else
+           0
+         end
+       }.reduce(:+) %>
+
+    <%= runtime(runningtime, true) %><% if tasks.size == 0 %>.<% else %>,
+      using
+      <% cputime = tasks.map { |task|
+                  if task.started_at
+                    (if task.finished_at then task.finished_at else Time.now() end) - task.started_at
+                  else
+                    0
+                  end
+                }.reduce(:+) %>
+    <%= runtime(cputime, true) %>
+    of CPU time (<%= (cputime/runningtime).round(1) %>⨯ scaling).
+    <% end %>
+</p>
+
+<%# Components %>
+
+<% render_pipeline_jobs.each_index do |i| %>
+  <% pj = render_pipeline_jobs[i] %>
+  <% current_job = pj[:job] if pj[:job] != {} %>
+  <div class="panel panel-default">
+    <div class="panel-heading">
+      <div class="container-fluid">
+        <div class="row">
+          <div class="col-md-3">
+            <h4 class="panel-title">
+              <a data-toggle="collapse" data-parent="#accordion" href="#collapse<%= i %>">
+                <%= pj[:name] %> <span class="caret"></span>
+              </a>
+            </h4>
+          </div>
+
+          <% puts current_job.inspect %>
+
+          <% if current_job %>
+            <div class="col-md-3">
+              <% if current_job.started_at %>
+                <% walltime = ((if current_job.finished_at then current_job.finished_at else Time.now() end) - current_job.started_at) %>
+                <% cputime = tasks.map { |task|
+                     if task.started_at and task.job_uuid == current_job.uuid
+                       (if task.finished_at then task.finished_at else Time.now() end) - task.started_at
+                     else
+                       0
+                     end
+                   }.reduce(:+) %>
+                <%= runtime(walltime, false) %> / <%= runtime(cputime, false) %> (<%= (cputime/walltime).round(1) %>⨯)
               <% end %>
+            </div>
+
+            <% if current_job.state.in? ["Completed", "Failed", "Canceled"] %>
+              <div class="col-md-3">
+                <%= render(partial: 'job_status_label', locals: { j: current_job }) %>
+              </div>
+              <div class="col-md-3">
+                <% if pj[:output_uuid] %>
+                  <%= link_to_if_arvados_object pj[:output_uuid] %>
+                <% elsif current_job.andand[:output] %>
+                  <%= link_to_if_arvados_object current_job[:output], link_text: "Output of #{pj[:name]}" %>
+                <% end %>
+              </div>
+            <% elsif current_job.state == "Running" %>
+              <div class="col-md-3">
+                <%= pj[:progress_bar] %>
+              </div>
+              <div class="col-md-3">
+                <%= form_tag "/jobs/#{current_job.uuid}/cancel", style: "display:inline; padding-left: 1em" do |f| %>
+                <%= hidden_field_tag :return_to, url_for(@object) %>
+                <%= button_tag "Cancel", {class: 'btn btn-danger', id: "cancel-job-button"} %>
+            </div>
             <% end %>
-          </td><td>
-            <% if pj[:output_uuid] %>
-                <%= link_to_if_arvados_object pj[:output_uuid], {thumbnail: true, link_text: raw('<i class="fa fa-fw fa-archive"></i> Show output files')}, {class: 'btn btn-default btn-xs'} %>
-            <% elsif current_job.andand[:output] %>
-                <%= link_to_if_arvados_object current_job[:output], {thumbnail: true, link_text: raw('<i class="fa fa-fw fa-archive"></i> Show output files')}, {class: 'btn btn-default btn-xs'} %>
-            <% end %>
-          </td>
-        </tr>
-      <% end %>
-    </tbody>
-    <tfoot>
-      <tr><td colspan="7"></td></tr>
-    </tfoot>
-  </table>
+          <% elsif current_job.state == "Queued" %>
+            <div class="col-md-1">
+              <span class="label label-default">Queued</span>
+            </div>
+            <div class="col-md-5">
+              <% queuetime = Time.now - current_job.created_at %>
+              Queued for <%= runtime(queuetime, true) %>.
+                There
+              <% if current_job.queue_position == 0 %>
+                are no jobs
+              <% elsif current_job.queue_position == 1 %>
+                is 1 job
+              <% else  %>
+                <%= current_job.queue_position %> jobs
+              <% end %>
+                ahead of this one.
+            </div>
+          <% end %>
+        <% else %>
+          <div class="col-md-3 col-md-offset-3">
+            <span class="label label-default">Not ready</span>
+          </div>
+<% end %>
+</div>
+</div>
+</div>
+
+<div id="collapse<%= i %>" class="panel-collapse collapse in">
+  <div class="panel-body">
+    <div class="container">
+        <% current_component = (if current_job then current_job else pj end) %>
+        <div class="row">
+          <div class="col-md-6">
+            <table>
+              <% [:script, :repository, :supplied_script_version, :script_version, :nondeterministic].each do |k| %>
+                <tr>
+                  <td style="padding-right: 1em">
+                    <%= k.to_s %>:
+                  </td>
+                  <td>
+                    <%= current_component[k] %>
+                  </td>
+                </tr>
+              <% end %>
+              <% if current_component[:runtime_constraints].andand[:docker_image] and current_component[:docker_image_locator] %>
+                <tr>
+                  <td style="padding-right: 1em">
+                    docker_image:
+                  </td>
+                  <td>
+                    <%= current_component[:runtime_constraints][:docker_image] %>
+                  </td>
+                </tr>
+                <tr>
+                  <td style="padding-right: 1em">
+                    docker_image_locator:
+                  </td>
+                  <td>
+                    <%= link_to_if_arvados_object current_component[:docker_image_locator] %>
+                  </td>
+                </tr>
+              <% else %>
+                <tr>
+                  <td style="padding-right: 1em">
+                    docker_image:
+                  </td>
+                  <td>
+                    Not run in Docker
+                  </td>
+                </tr>
+              <% end %>
+            </table>
+          </div>
+          <div class="col-md-5">
+            <table>
+              <% [:uuid, :modified_by_user_uuid, :priority, :created_at, :started_at, :finished_at].each do |k| %>
+                <tr>
+                  <td style="padding-right: 1em">
+                    <%= k.to_s %>:
+                  </td>
+                  <td>
+                    <% if k.to_s.end_with? 'uuid' %>
+                      <%= link_to_if_arvados_object current_component[k], friendly_name: true %>
+                    <% else %>
+                      <%= current_component[k] %>
+                    <% end %>
+                  </td>
+                </tr>
+              <% end %>
+            </table>
+          </div>
+        </div>
+        <div class="row">
+          <div class="col-md-6">
+            <p>script_parameters:</p>
+            <pre><%= JSON.pretty_generate(current_component[:script_parameters]) rescue nil %></pre>
+          </div>
+          <% if current_component[:tasks_summary] %>
+          <div class="col-md-3">
+            <table>
+              <% [:done, :running, :failed, :todo].each do |d| %>
+              <tr>
+                <td style="padding-right: 1em"><%= 'tasks:' if d == :done %></td>
+                <td style="padding-right: 1em"><%= d.to_s %></td>
+                <td><%= current_component[:tasks_summary][d] %></td>
+              </tr>
+              <% end %>
+            </table>
+          </div>
+          <% end %>
+        </div>
+    </div>
+  </div>
+</div>
+</div>
+<% end %>
diff --git a/apps/workbench/app/views/pipeline_instances/show.html.erb b/apps/workbench/app/views/pipeline_instances/show.html.erb
index b30db3b..f43369f 100644
--- a/apps/workbench/app/views/pipeline_instances/show.html.erb
+++ b/apps/workbench/app/views/pipeline_instances/show.html.erb
@@ -12,12 +12,21 @@
 <% end %>
 
 <% content_for :tab_line_buttons do %>
-  <%= link_to(copy_pipeline_instance_path('id' => @object.uuid, 'pipeline_instance[state]' => 'New'),
+
+  <% if @object.state.in? ['Complete', 'Failed', 'Cancelled'] %>
+
+  <%= link_to(copy_pipeline_instance_path('id' => @object.uuid, 'script' => "use_latest", "components" => "use_latest", "pipeline_instance[state]" => "RunningOnServer"),
       class: 'btn btn-primary',
-      #data: {toggle: :tooltip, placement: :top}, title: 'copy and modify',
+      #data: {toggle: :tooltip, placement: :top}, title: 'Re-run',
       method: :post,
       ) do %>
-    Clone and edit <i class="fa fa-fw fa-copy"></i>
+    <i class="fa fa-fw fa-play"></i> Re-run with latest
+  <% end %>
+
+  <%= link_to raw('<i class="fa fa-fw fa-cogs"></i> Re-run options'),
+      "#",
+      {class: 'btn btn-primary', 'data-toggle' =>  "modal",
+        'data-target' => '#clone-and-edit-modal-window'}  %>
   <% end %>
 
   <% if @object.state.in? ['New', 'Ready'] %>
@@ -25,7 +34,7 @@
         class: 'btn btn-primary run-pipeline-button',
         method: :patch
         ) do %>
-      Run <i class="fa fa-fw fa-play"></i>
+      <i class="fa fa-fw fa-play"></i> Run
     <% end %>
   <% else %>
     <% if @object.state.in? ['RunningOnClient', 'RunningOnServer'] %>
@@ -33,17 +42,60 @@
           class: 'btn btn-primary run-pipeline-button',
           method: :patch
           ) do %>
-        Stop <i class="fa fa-fw fa-stop"></i>
+        <i class="fa fa-fw fa-pause"></i> Pause
       <% end %>
     <% elsif @object.state == 'Paused' %>
       <%= link_to(url_for('pipeline_instance[state]' => 'RunningOnServer'),
           class: 'btn btn-primary run-pipeline-button',
           method: :patch
           ) do %>
-        Resume <i class="fa fa-fw fa-play"></i>
+        <i class="fa fa-fw fa-play"></i> Resume
       <% end %>
     <% end %>
   <% end %>
 <% end %>
 
 <%= render partial: 'content', layout: 'content_layout', locals: {pane_list: controller.show_pane_list }%>
+
+<div id="clone-and-edit-modal-window" class="modal fade" role="dialog"
+     aria-labelledby="myModalLabel" aria-hidden="true">
+  <div class="modal-dialog">
+    <div class="modal-content">
+
+    <%= form_tag copy_pipeline_instance_path do |f| %>
+
+      <div class="modal-header">
+        <button type="button" class="close" onClick="reset_form()" data-dismiss="modal" aria-hidden="true">×</button>
+        <div>
+          <div class="col-sm-6"> <h4 class="modal-title">Re-run pipeline</h4> </div>
+        </div>
+        <br/>
+      </div>
+
+      <div class="modal-body">
+              <%= radio_button_tag(:script, "use_latest", true) %>
+              <%= label_tag(:script_use_latest, "Use latest script versions") %>
+              <br>
+              <%= radio_button_tag(:script, "use_same") %>
+              <%= label_tag(:script_use_same, "Use same script versions as this run") %>
+              <br>
+              <% if template %>
+              <br>
+              <%= radio_button_tag(:components, "use_latest", true) %>
+              <%= label_tag(:components_use_latest, "Update components against template") %>
+              <br>
+              <%= radio_button_tag(:components, "use_same") %>
+              <%= label_tag(:components_use_same, "Use same components as this run") %>
+              <% end %>
+      </div>
+
+      <div class="modal-footer">
+        <button type="submit" class="btn btn-primary" name="pipeline_instance[state]" value="New">Copy and edit inputs</button>
+        <button type="submit" class="btn btn-primary" name="pipeline_instance[state]" value="RunningOnServer">Run now</button>
+        <button class="btn btn-default" onClick="reset_form()" data-dismiss="modal" aria-hidden="true">Cancel</button>
+      </div>
+
+    </div>
+    <% end %>
+  </div>
+</div>

commit 0313c6ef5ac52fc483718690b1a5902ad1c11e16
Author: Peter Amstutz <peter.amstutz at curoverse.com>
Date:   Wed Sep 10 17:01:01 2014 -0400

    3187: Added queue_position field to job response.

diff --git a/services/api/app/models/job.rb b/services/api/app/models/job.rb
index 75de61c..6e87bda 100644
--- a/services/api/app/models/job.rb
+++ b/services/api/app/models/job.rb
@@ -40,6 +40,7 @@ class Job < ArvadosModel
     t.add :repository
     t.add :supplied_script_version
     t.add :docker_image_locator
+    t.add :queue_position
   end
 
   def assert_finished
@@ -54,6 +55,16 @@ class Job < ArvadosModel
       order('priority desc, created_at')
   end
 
+  def queue_position
+    i = 0
+    Job::queue.each do |j|
+      if j[:uuid] == self.uuid
+        return i
+      end
+    end
+    nil
+  end
+
   def self.running
     self.where('running = ?', true).
       order('priority desc, created_at')

commit 655d5ae89e941c8b11bd4ba795e9ef2168463881
Author: Peter Amstutz <peter.amstutz at curoverse.com>
Date:   Tue Sep 9 15:39:55 2014 -0400

    3187: Record started_at and finished_at for tasks and pipelines.

diff --git a/sdk/cli/bin/arv-run-pipeline-instance b/sdk/cli/bin/arv-run-pipeline-instance
index 7ce1fa9..b19bf04 100755
--- a/sdk/cli/bin/arv-run-pipeline-instance
+++ b/sdk/cli/bin/arv-run-pipeline-instance
@@ -495,6 +495,10 @@ class WhRunPipelineInstance
     moretodo = true
     interrupted = false
 
+    if @instance[:started_at].nil?
+      @instance[:started_at] = Time.now
+    end
+
     job_creation_failed = 0
     while moretodo
       moretodo = false
@@ -598,7 +602,7 @@ class WhRunPipelineInstance
                       owner_uuid: owner_uuid,
                       name: name,
                       portable_data_hash: collections.first[:portable_data_hash],
-                      manifest_text: collections.first[:manifest_text]                      
+                      manifest_text: collections.first[:manifest_text]
                     }
                     debuglog "Creating collection #{newcollection}", 0
                     newcollection_actual = $arv.collection.create collection: newcollection, ensure_unique_name: true
@@ -679,6 +683,10 @@ class WhRunPipelineInstance
       end
     end
 
+    if @instance[:finished_at].nil? and ['Complete', 'Failed'].include? @instance[:state]
+      @instance[:finished_at] = Time.now
+    end
+
     debuglog "pipeline instance state is #{@instance[:state]}"
 
     # set components_summary
@@ -742,6 +750,7 @@ class WhRunPipelineInstance
       if ["New", "Ready", "RunningOnClient",
           "RunningOnServer"].include?(@instance[:state])
         @instance[:state] = "Failed"
+        @instance[:finished_at] = Time.now
         @instance.save
       end
       @instance.log_stderr(msg)
diff --git a/sdk/cli/bin/crunch-job b/sdk/cli/bin/crunch-job
index a2c5512..06144fd 100755
--- a/sdk/cli/bin/crunch-job
+++ b/sdk/cli/bin/crunch-job
@@ -74,6 +74,7 @@ behavior (e.g., cancel job if cancelled_at becomes non-nil).
 
 use strict;
 use POSIX ':sys_wait_h';
+use POSIX qw(strftime);
 use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK);
 use Arvados;
 use Digest::MD5 qw(md5_hex);
@@ -979,6 +980,9 @@ sub reapchildren
   }
   $Jobstep->{exitcode} = $childstatus;
   $Jobstep->{finishtime} = time;
+  $Jobstep->{'arvados_task'}->{started_at} = strftime "Y%-%m-%dT%H:%M:%SZ", gmtime($Jobstep->{starttime});
+  $Jobstep->{'arvados_task'}->{finished_at} = strftime "Y%-%m-%dT%H:%M:%SZ", gmtime($Jobstep->{finishtime});
+  $Jobstep->{'arvados_task'}->save;
   process_stderr ($jobstepid, $task_success);
   Log ($jobstepid, "output " . $Jobstep->{'arvados_task'}->{output});
 

commit e5ab4ce19d5ace5e6dd5cd32c23f50b35d20c8ef
Author: Peter Amstutz <peter.amstutz at curoverse.com>
Date:   Tue Sep 9 14:43:29 2014 -0400

    3187: Migration to add started_at and finished_at to job_tasks and pipeline_instances.

diff --git a/services/api/app/models/job_task.rb b/services/api/app/models/job_task.rb
index 4dcf256..5f83fbe 100644
--- a/services/api/app/models/job_task.rb
+++ b/services/api/app/models/job_task.rb
@@ -15,6 +15,8 @@ class JobTask < ArvadosModel
     t.add :output
     t.add :progress
     t.add :success
+    t.add :started_at
+    t.add :finished_at
   end
 
   protected
diff --git a/services/api/app/models/pipeline_instance.rb b/services/api/app/models/pipeline_instance.rb
index 354c892..7523918 100644
--- a/services/api/app/models/pipeline_instance.rb
+++ b/services/api/app/models/pipeline_instance.rb
@@ -22,6 +22,8 @@ class PipelineInstance < ArvadosModel
     t.add :properties
     t.add :state
     t.add :components_summary
+    t.add :started_at
+    t.add :finished_at
   end
 
   # Supported states for a pipeline instance
diff --git a/services/api/db/migrate/20140909183946_add_start_finish_time_to_tasks_and_pipelines.rb b/services/api/db/migrate/20140909183946_add_start_finish_time_to_tasks_and_pipelines.rb
new file mode 100644
index 0000000..139cb8d
--- /dev/null
+++ b/services/api/db/migrate/20140909183946_add_start_finish_time_to_tasks_and_pipelines.rb
@@ -0,0 +1,15 @@
+class AddStartFinishTimeToTasksAndPipelines < ActiveRecord::Migration
+  def up
+    add_column :job_tasks, :started_at, :datetime
+    add_column :job_tasks, :finished_at, :datetime
+    add_column :pipeline_instances, :started_at, :datetime
+    add_column :pipeline_instances, :finished_at, :datetime
+  end
+
+  def down
+    remove_column :job_tasks, :started_at
+    remove_column :job_tasks, :finished_at
+    remove_column :pipeline_instances, :started_at
+    remove_column :pipeline_instances, :finished_at
+  end
+end
diff --git a/services/api/db/structure.sql b/services/api/db/structure.sql
index bd86826..2168739 100644
--- a/services/api/db/structure.sql
+++ b/services/api/db/structure.sql
@@ -353,7 +353,9 @@ CREATE TABLE job_tasks (
     created_at timestamp without time zone NOT NULL,
     updated_at timestamp without time zone NOT NULL,
     created_by_job_task_uuid character varying(255),
-    qsequence bigint
+    qsequence bigint,
+    started_at timestamp without time zone,
+    finished_at timestamp without time zone
 );
 
 
@@ -678,7 +680,9 @@ CREATE TABLE pipeline_instances (
     properties text,
     state character varying(255),
     components_summary text,
-    description text
+    description text,
+    started_at timestamp without time zone,
+    finished_at timestamp without time zone
 );
 
 
@@ -2012,3 +2016,5 @@ INSERT INTO schema_migrations (version) VALUES ('20140818125735');
 INSERT INTO schema_migrations (version) VALUES ('20140826180337');
 
 INSERT INTO schema_migrations (version) VALUES ('20140828141043');
+
+INSERT INTO schema_migrations (version) VALUES ('20140909183946');
\ No newline at end of file

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


hooks/post-receive
-- 




More information about the arvados-commits mailing list