9767: include workflows in the template chooser.
authorradhika <radhika@curoverse.com>
Fri, 19 Aug 2016 17:54:19 +0000 (13:54 -0400)
committerradhika <radhika@curoverse.com>
Thu, 25 Aug 2016 15:44:50 +0000 (11:44 -0400)
17 files changed:
apps/workbench/Gemfile
apps/workbench/Gemfile.lock
apps/workbench/app/controllers/work_unit_templates_controller.rb [new file with mode: 0644]
apps/workbench/app/controllers/work_units_controller.rb
apps/workbench/app/models/container_work_unit.rb
apps/workbench/app/models/pipeline_instance_work_unit.rb
apps/workbench/app/models/work_unit.rb
apps/workbench/app/views/application/_choose_rows.html.erb [new file with mode: 0644]
apps/workbench/app/views/projects/_show_dashboard.html.erb
apps/workbench/app/views/projects/show.html.erb
apps/workbench/app/views/workflows/_show_chooser_preview.html.erb [new file with mode: 0644]
apps/workbench/config/load_config.rb
apps/workbench/config/routes.rb
apps/workbench/test/integration/application_layout_test.rb
apps/workbench/test/integration/projects_test.rb
services/api/Gemfile.lock
services/api/test/fixtures/workflows.yml

index db569c96a5dcddaaa47b4aaf49ff2cbe40244ef8..20d64d17a16dc87b2a076c13b2ad6c356b0a041a 100644 (file)
@@ -96,3 +96,5 @@ gem 'raphael-rails'
 
 gem 'lograge'
 gem 'logstash-event'
+
+gem 'safe_yaml'
index 03bbbce0614eb37411ac993ea1d8af0d2f3bbdeb..a8431a7dfd373d0357053df0e06df901498ca0ca 100644 (file)
@@ -216,6 +216,7 @@ GEM
     rubyzip (1.1.7)
     rvm-capistrano (1.5.5)
       capistrano (~> 2.15.4)
+    safe_yaml (1.0.4)
     sass (3.4.9)
     sass-rails (5.0.1)
       railties (>= 4.0.0, < 5.0)
@@ -306,6 +307,7 @@ DEPENDENCIES
   ruby-debug-passenger
   ruby-prof
   rvm-capistrano
+  safe_yaml
   sass
   sass-rails
   selenium-webdriver
diff --git a/apps/workbench/app/controllers/work_unit_templates_controller.rb b/apps/workbench/app/controllers/work_unit_templates_controller.rb
new file mode 100644 (file)
index 0000000..6b5f114
--- /dev/null
@@ -0,0 +1,30 @@
+class WorkUnitTemplatesController < ApplicationController
+  def find_objects_for_index
+    return if !params[:partial]
+
+    @limit = 40
+    @filters = @filters || []
+
+    # get next page of pipeline_templates
+    filters = @filters + [["uuid", "is_a", ["arvados#pipelineTemplate"]]]
+    pipelines = PipelineTemplate.limit(@limit).order(["created_at desc"]).filter(filters)
+
+    # get next page of workflows
+    filters = @filters + [["uuid", "is_a", ["arvados#workflow"]]]
+    workflows = Workflow.limit(@limit).order(["created_at desc"]).filter(filters)
+
+    @objects = (pipelines.to_a + workflows.to_a).sort_by(&:created_at).reverse.first(@limit)
+
+    if @objects.any?
+      @next_page_filters = next_page_filters('<=')
+      @next_page_href = url_for(partial: :choose_rows,
+                                filters: @next_page_filters.to_json)
+    else
+      @next_page_href = nil
+    end
+  end
+
+  def next_page_href with_params={}
+    @next_page_href
+  end
+end
index ff69d89fda423d52b63b70b0ef6bf328d2fdd3d3..0c8ea6e70420f542846b8de2eafe52f62c07f54b 100644 (file)
@@ -34,4 +34,81 @@ class WorkUnitsController < ApplicationController
   def next_page_href with_params={}
     @next_page_href
   end
+
+  def create
+    template_uuid = params['work_unit']['template_uuid']
+
+    attrs = {}
+    rc = resource_class_for_uuid(template_uuid)
+    if rc == PipelineTemplate
+      model_class = PipelineInstance
+      attrs['pipeline_template_uuid'] = template_uuid
+    elsif rc == Workflow
+      # workflow json
+      workflow = Workflow.find? template_uuid
+      if workflow.workflow
+        begin
+          wf_json = YAML::load(workflow.workflow)
+        rescue => e
+          logger.error "Error converting workflow yaml to json: #{e.message}"
+          raise ArgumentError, "Error converting workflow yaml to json: #{e.message}"
+        end
+      end
+
+      model_class = ContainerRequest
+
+      attrs['name'] = "#{workflow['name']} container" if workflow['name'].present?
+      attrs['properties'] = {'template_uuid' => template_uuid}
+      attrs['priority'] = 1
+      attrs['state'] = "Uncommitted"
+
+      # required
+      attrs['command'] = ["arvados-cwl-runner", "--local", "--api=containers", "/var/lib/cwl/workflow.json", "/var/lib/cwl/cwl.input.json"]
+      attrs['container_image'] = "arvados/jobs"
+      attrs['cwd'] = "/var/spool/cwl"
+      attrs['output_path'] = "/var/spool/cwl"
+
+      # mounts
+      mounts = {
+        "/var/lib/cwl/cwl.input.json" => {
+          "kind" => "json",
+          "content" => {}
+        },
+        "stdout" => {
+          "kind" => "file",
+          "path" => "/var/spool/cwl/cwl.output.json"
+        },
+        "/var/spool/cwl" => {
+          "kind" => "collection",
+          "writable" => true
+        }
+      }
+      if wf_json
+        mounts["/var/lib/cwl/workflow.json"] = {
+          "kind" => "json",
+          "content" => wf_json
+        }
+      end
+      attrs['mounts'] = mounts
+
+      # runtime constriants
+      runtime_constraints = {
+        "vcpus" => 1,
+        "ram" => 256000000,
+        "API" => true
+      }
+      attrs['runtime_constraints'] = runtime_constraints
+    else
+      raise ArgumentError, "Unsupported template uuid: #{template_uuid}"
+    end
+
+    attrs['owner_uuid'] = params['work_unit']['owner_uuid']
+    @object ||= model_class.new attrs
+
+    if @object.save
+      redirect_to @object
+    else
+      render_error status: 422
+    end
+  end
 end
index 4f4c915e066ce3d8c2ef4427336e5a71b0b87b2e..1ed182c35f8482e39537e0591c849f8538d5934f 100644 (file)
@@ -142,6 +142,13 @@ class ContainerWorkUnit < ProxyWorkUnit
     end
   end
 
+  def template_uuid
+    properties = get(:properties)
+    if properties
+      properties[:workflow_uuid]
+    end
+  end
+
   # End combined propeties
 
   protected
index 889fa1a7f3cccecf86c53f5cd837ad4f34cb7ca2..dd5685ac3d8082d5a5836896afa310b416e728f2 100644 (file)
@@ -51,4 +51,8 @@ class PipelineInstanceWorkUnit < ProxyWorkUnit
   def title
     "pipeline"
   end
+
+  def template_uuid
+    get(:pipeline_template_uuid)
+  end
 end
index 0d194b88a5f8c70a09a4f6044c0a6f90ab388b07..7373bc242353b99c43f3cd73708e1ce9c7235599 100644 (file)
@@ -195,4 +195,8 @@ class WorkUnit
   def render_log
     # return partial and locals to be rendered
   end
+
+  def template_uuid
+    # return the uuid of this work unit's template, if one exists
+  end
 end
diff --git a/apps/workbench/app/views/application/_choose_rows.html.erb b/apps/workbench/app/views/application/_choose_rows.html.erb
new file mode 100644 (file)
index 0000000..9b96b47
--- /dev/null
@@ -0,0 +1,8 @@
+<% @objects.each do |object| %>
+  <div class="row filterable selectable" data-object-uuid="<%= object.uuid %>" data-preview-href="<%= url_for object %>?tab_pane=chooser_preview">
+    <div class="col-sm-12" style="overflow-x:hidden">
+      <i class="fa fa-fw fa-gear"></i>
+      <%= object.name %>
+    </div>
+  </div>
+<% end %>
index afca2468d7aa86193d349d1aefee9b6f82d1170f..e8742f424697f0b7cfed91c9e212e441efcf5230 100644 (file)
@@ -7,12 +7,12 @@
             <span class="pull-right recent-processes-actions">
               <span>
                 <%= link_to(
-                choose_pipeline_templates_path(
-                  title: 'Choose a pipeline to run:',
+                choose_work_unit_templates_path(
+                  title: 'Choose a pipeline or workflow to run:',
                   action_name: 'Next: choose inputs <i class="fa fa-fw fa-arrow-circle-right"></i>',
-                  action_href: pipeline_instances_path,
+                  action_href: work_units_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),
+                  action_data: {'selection_param' => 'work_unit[template_uuid]', 'work_unit[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 %>
index 6033a3491051d657bfb470eb351f2df710edb90c..e52d826cf60da778f9b343d1d44578c6cc5b0c7f 100644 (file)
       </ul>
     </div>
     <%= link_to(
-          choose_pipeline_templates_path(
-            title: 'Choose a pipeline to run:',
+          choose_work_unit_templates_path(
+            title: 'Choose a pipeline or workflow to run:',
             action_name: 'Next: choose inputs <i class="fa fa-fw fa-arrow-circle-right"></i>',
-            action_href: pipeline_instances_path,
+            action_href: work_units_path,
             action_method: 'post',
-            action_data: {'selection_param' => 'pipeline_instance[pipeline_template_uuid]', 'pipeline_instance[owner_uuid]' => @object.uuid, 'success' => 'redirect-to-created-object'}.to_json),
-          { class: "btn btn-primary btn-sm", remote: true, title: "Run a pipeline in this project" }) do %>
+            action_data: {'selection_param' => 'work_unit[template_uuid]', 'work_unit[owner_uuid]' => @object.uuid, 'success' => 'redirect-to-created-object'}.to_json),
+          { class: "btn btn-primary btn-sm", remote: true, title: "Run a pipeline or workflow in this project" }) do %>
       <i class="fa fa-fw fa-gear"></i> Run a pipeline...
     <% end %>
     <%= link_to projects_path({'project[owner_uuid]' => @object.uuid, 'options' => {'ensure_unique_name' => true}}), method: :post, title: "Add a subproject to this project", class: 'btn btn-sm btn-primary' do %>
diff --git a/apps/workbench/app/views/workflows/_show_chooser_preview.html.erb b/apps/workbench/app/views/workflows/_show_chooser_preview.html.erb
new file mode 100644 (file)
index 0000000..395dda9
--- /dev/null
@@ -0,0 +1,3 @@
+<div class="col-sm-11 col-sm-push-1 arv-description-in-table">
+  <%= (@object.description if @object.description.present?) || 'No description' %>
+</div>
index f14c3ca8456b3b252574027f3b4ba53ad501ff85..95f6edc95267a04e9dbb97fd6d56799575f9ea83 100644 (file)
@@ -7,7 +7,7 @@ $application_config = {}
   path = "#{::Rails.root.to_s}/config/#{cfgfile}.yml"
   if File.exists? path
     yaml = ERB.new(IO.read path).result(binding)
-    confs = YAML.load(yaml)
+    confs = YAML.load(yaml, deserialize_symbols: true)
     $application_config.merge!(confs['common'] || {})
     $application_config.merge!(confs[::Rails.env.to_s] || {})
   end
index 5d02e57ac74c42d72b7e7ee5ebf3ed8dcee8588e..7f7854864190318171750cb498a0dc7d941156c9 100644 (file)
@@ -14,6 +14,8 @@ ArvadosWorkbench::Application.routes.draw do
   post "report_issue" => 'actions#report_issue', :as => :report_issue
   get "star" => 'actions#star', :as => :star
   get "all_processes" => 'work_units#index', :as => :all_processes
+  get "choose_work_unit_templates" => 'work_unit_templates#choose', :as => :choose_work_unit_templates
+  resources :work_units
   resources :nodes
   resources :humans
   resources :traits
index 40ec31d74e47eacedd672ee9f4ef8064b629a3ad..3edd660e3d1db39b43bcb5b8cf82b09437fe7413 100644 (file)
@@ -335,4 +335,29 @@ class ApplicationLayoutTest < ActionDispatch::IntegrationTest
       assert page.has_text? 'Textile description for object'
     end
   end
+
+  [
+    ['Two Part Pipeline Template', 'part-one', 'Provide a value for the following'],
+    ['Workflow with input specifications', 'this work has inputs specified', 'This container is uncommitted'],
+  ].each do |template_name, preview_txt, process_txt|
+    test "run a process using template #{template_name} from dashboard" do
+      visit page_with_token('admin')
+      assert_text 'Recent pipelines and processes' # seeing dashboard now
+
+      within('.recent-processes-actions') do
+        assert page.has_link?('All processes')
+        find('a', text: 'Run a pipeline').click
+      end
+
+      # in the chooser, verify preview and click Next button
+      within('.modal-dialog') do
+        find('.selectable', text: template_name).click
+        assert_text preview_txt
+        find('.btn', text: 'Next: choose inputs').click
+      end
+
+      # in the process page now
+      assert_text process_txt
+    end
+  end
 end
index 1c18a436fdbb3fcbaab3de74e9a350ce3e87bbab..626bd50950c99c06c3efc545204a8f41b227ec7d 100644 (file)
@@ -737,4 +737,27 @@ class ProjectsTest < ActionDispatch::IntegrationTest
       assert_no_selector 'li', text: 'Unrestricted public data'
     end
   end
+
+  [
+    ['Two Part Pipeline Template', 'part-one', 'Provide a value for the following'],
+    ['Workflow with input specifications', 'this work has inputs specified', 'This container is uncommitted'],
+  ].each do |template_name, preview_txt, process_txt|
+    test "run a process using template #{template_name} in a project" do
+      project = api_fixture('groups')['aproject']
+      visit page_with_token 'active', '/projects/' + project['uuid']
+
+      find('.btn', text: 'Run a pipeline').click
+
+      # in the chooser, verify preview and click Next button
+      within('.modal-dialog') do
+        find('.selectable', text: template_name).click
+        assert_text preview_txt
+        find('.btn', text: 'Next: choose inputs').click
+      end
+
+      # in the process page now
+      assert_text process_txt
+      assert_text project['name']
+    end
+  end
 end
index 391a26c2a859945635772864a8d0ef642c7d47be..1fb4369c0eca56815d189b4a9c5bf7f87ab9e4ea 100644 (file)
@@ -266,6 +266,3 @@ DEPENDENCIES
   therubyracer
   trollop
   uglifier (>= 1.0.3)
-
-BUNDLED WITH
-   1.12.1
index d7818f26f3c75cd891a2144c3f8cf35192ed9ca1..8e32409c211f98121fa09714b73bdeaa5e9f4bb7 100644 (file)
@@ -1,17 +1,46 @@
 workflow_with_workflow_yml:
   uuid: zzzzz-7fd4e-validworkfloyml
   owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
-  name: Valid workflow
+  name: Valid workflow with name and desc
   description: this work has a valid workflow yaml
   workflow: "name: foo\ndesc: bar"
+  created_at: 2016-08-15 12:00:00
 
 workflow_with_no_workflow_yml:
   uuid: zzzzz-7fd4e-validbutnoyml00
   owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
   name: Valid workflow with no workflow yaml
   description: this workflow does not have a workflow yaml
+  created_at: 2016-08-15 12:00:00
 
 workflow_with_no_name_and_desc:
   uuid: zzzzz-7fd4e-validnonamedesc
   owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
   workflow: this is valid yaml
+  created_at: 2016-08-15 12:00:01
+
+workflow_with_input_specifications:
+  uuid: zzzzz-7fd4e-validwithinputs
+  owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
+  name: Workflow with input specifications
+  description: this work has inputs specified
+  created_at: <%= 1.minute.ago.to_s(:db) %>
+  workflow:
+    cwlVersion: v1.0
+    class: CommandLineTool
+    baseCommand:
+    - echo
+    inputs:
+    - doc: a longer documentation string for this parameter (optional)
+      type: boolean
+      id: ex_boolean
+      label: a short label for this parameter (optional)
+      inputBinding:
+        position: 1
+    - type:
+      - 'null'
+      - boolean
+      id: ex_boolean_opt
+      inputBinding:
+        position: 1
+    outputs: []