Merge branch '17246-salt-install-improvements'
[arvados.git] / apps / workbench / app / helpers / provenance_helper.rb
index 3567cbaee6258d399783b85b4f953e9fcd3f519b..cef5cc7ee816db5e906537e6da643b33223466f7 100644 (file)
@@ -1,3 +1,7 @@
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: AGPL-3.0
+
 module ProvenanceHelper
 
   class GenerateGraph
@@ -110,19 +114,6 @@ module ProvenanceHelper
       gr
     end
 
-    def cr_input_pdhs cr
-      pdhs = []
-      input_obj = cr[:mounts].andand[:"/var/lib/cwl/cwl.input.json"].andand[:content] || cr[:mounts]
-      if input_obj
-        ProvenanceHelper::find_collections input_obj do |col_hash, col_uuid, key|
-          if col_hash
-            pdhs << col_hash
-          end
-        end
-      end
-      pdhs
-    end
-
     def job_edges job, edge_opts={}
       uuid = job_uuid(job)
       gr = ""
@@ -160,6 +151,83 @@ module ProvenanceHelper
       gr
     end
 
+    def cr_edges cont, edge_opts={}
+      uuid = cont[:uuid]
+      gr = ""
+
+      gr += describe_node(cont[:uuid], {href: {controller: 'container_requests',
+                                             id: cont[:uuid]},
+                                        shape: 'oval',
+                                        label: cont[:name]})
+
+      ProvenanceHelper::find_collections cont[:mounts] do |collection_hash, collection_uuid, key|
+        if @opts[:pdh_to_uuid] and @opts[:pdh_to_uuid][collection_hash]
+          collection_uuid = @opts[:pdh_to_uuid][collection_hash].uuid
+          collection_hash = nil
+        end
+        if collection_uuid and @pdata[collection_uuid]
+          gr += describe_node(collection_uuid)
+          gr += edge(collection_uuid, uuid, {:label => key})
+        elsif collection_hash and @pdata[collection_hash]
+          gr += describe_node(collection_hash)
+          gr += edge(collection_hash, uuid, {:label => key})
+        end
+      end
+
+      if cont[:container_image] and !@opts[:no_docker] and @pdata[cont[:container_image]]
+        gr += describe_node(cont[:container_image], {label: cont[:container_image]})
+        gr += edge(cont[:container_image], uuid, {label: "docker_image"})
+      end
+
+      if cont[:output_uuid] and !edge_opts[:no_output] and @pdata[cont[:output_uuid]]
+        gr += describe_node(cont[:output_uuid])
+        gr += edge(uuid, cont[:output_uuid], {label: "output" })
+      end
+
+      if cont[:log_uuid] and !edge_opts[:no_log] and @pdata[cont[:log_uuid]]
+        gr += describe_node(cont[:log_uuid])
+        gr += edge(uuid, cont[:log_uuid], {label: "log"})
+      end
+
+      gr
+    end
+
+    def container_edges cont, edge_opts={}
+      uuid = cont[:uuid]
+      gr = ""
+
+      gr += describe_node(cont[:uuid], {href: {controller: 'containers',
+                                             id: cont[:uuid]},
+                                      shape: 'oval'})
+
+      ProvenanceHelper::find_collections cont[:mounts] do |collection_hash, collection_uuid, key|
+        if collection_uuid and @pdata[collection_uuid]
+          gr += describe_node(collection_uuid)
+          gr += edge(collection_uuid, uuid, {:label => key})
+        elsif collection_hash and @pdata[collection_hash]
+          gr += describe_node(collection_hash)
+          gr += edge(collection_hash, uuid, {:label => key})
+        end
+      end
+
+      if cont[:container_image] and !@opts[:no_docker] and @pdata[cont[:container_image]]
+        gr += describe_node(cont[:container_image], {label: cont[:container_image]})
+        gr += edge(cont[:container_image], uuid, {label: "docker_image"})
+      end
+
+      if cont[:output] and !edge_opts[:no_output] and @pdata[cont[:output]]
+        gr += describe_node(cont[:output])
+        gr += edge(uuid, cont[:output], {label: "output" })
+      end
+
+      if cont[:log] and !edge_opts[:no_log] and @pdata[cont[:log]]
+        gr += describe_node(cont[:log])
+        gr += edge(uuid, cont[:log], {label: "log"})
+      end
+
+      gr
+    end
+
     def generate_provenance_edges(uuid)
       gr = ""
       m = GenerateGraph::collection_uuid(uuid)
@@ -205,95 +273,10 @@ module ProvenanceHelper
           gr += job_edges job if job
         elsif rsc == ContainerRequest
           cr = @pdata[uuid]
-          if cr
-            child_crs = []
-            col_uuids = []
-            col_pdhs = []
-            col_uuids << cr[:output_uuid] if cr[:output_uuid]
-            col_pdhs += cr_input_pdhs(cr)
-            # Search for child CRs
-            if cr[:container_uuid]
-              child_crs = ContainerRequest.where(requesting_container_uuid: cr[:container_uuid])
-              child_crs.each do |child|
-                col_uuids << child[:output_uuid] if child[:output_uuid]
-                col_pdhs += cr_input_pdhs(child)
-              end
-            end
-
-            output_cols = {} # Indexed by UUID
-            input_cols = {} # Indexed by PDH
-
-            # Batch requests to get all related collections
-            Collection.filter([['uuid', 'in', col_uuids.uniq]]).each do |c|
-              output_cols[c[:uuid]] = c
-            end
-            output_pdhs = output_cols.values.map{|c| c[:portable_data_hash]}.uniq
-            Collection.filter([['portable_data_hash', 'in',  col_pdhs - output_pdhs]]).each do |c|
-              if input_cols[c[:portable_data_hash]]
-                input_cols[c[:portable_data_hash]] << c
-              else
-                input_cols[c[:portable_data_hash]] = [c]
-              end
-            end
-
-            # Make the graph
-            visited_pdhs = []
-            all_cr_nodes = [cr] + child_crs.results
-
-            # First pass: add the CR nodes with their outputs, because they're
-            # referenced by UUID.
-            all_cr_nodes.each do |cr_node|
-              # CR node
-              gr += describe_node(cr_node[:uuid], {href: {controller: 'container_requests',
-                                                          id: cr_node[:uuid]},
-                                                   label: cr_node[:name],
-                                                   shape: 'oval'})
-              # Connect child CRs with the main one
-              if cr_node != cr
-                gr += edge(cr_node[:uuid], cr[:uuid], {label: 'child'})
-              end
-              # Output collection node
-              if cr_node[:output_uuid] and output_cols[cr_node[:output_uuid]]
-                c = output_cols[cr_node[:output_uuid]]
-                visited_pdhs << c[:portable_data_hash]
-                gr += describe_node(c[:portable_data_hash],
-                                    {
-                                      label: c[:name],
-                                      col_uuid: c[:uuid],
-                                    })
-                gr += edge(cr_node[:uuid],
-                           c[:portable_data_hash],
-                           {label: 'output'})
-              end
-            end
-
-            # Second pass: add the input collection nodes.
-            all_cr_nodes.each do |cr_node|
-              cr_input_pdhs(cr_node).each do |pdh|
-                if not visited_pdhs.include?(pdh)
-                  visited_pdhs << pdh
-                  if input_cols[pdh]
-                    # First search for collections within the CR project
-                    cols = input_cols[pdh].select{|x| x[:owner_uuid] == cr_node[:owner_uuid]}
-                    if cols.empty?
-                      # Search for any collection with this PDH
-                      cols = input_cols[pdh]
-                    end
-                    names = cols.collect{|x| x[:name]}.uniq
-                    input_name = names.first
-                    if names.length > 1
-                      input_name += " + #{names.length - 1} others"
-                    end
-                  else
-                    # No collection found by this PDH
-                    input_name = pdh
-                  end
-                  gr += describe_node(pdh, {label: input_name})
-                end
-                gr += edge(pdh, cr_node[:uuid], {label: 'input'})
-              end
-            end
-          end
+          gr += cr_edges cr if cr
+        elsif rsc == Container
+          cr = @pdata[uuid]
+          gr += container_edges cr if cr
         end
       end
 
@@ -368,9 +351,8 @@ module ProvenanceHelper
 node [fontsize=10,fontname=\"Helvetica,Arial,sans-serif\"];
 edge [fontsize=10,fontname=\"Helvetica,Arial,sans-serif\"];
 """
-
-    if opts[:direction] == :bottom_up
-      gr += "edge [dir=back];"
+    if ["LR", "RL"].include? opts[:direction]
+      gr += "rankdir=#{opts[:direction]};"
     end
 
     begin
@@ -439,4 +421,17 @@ edge [fontsize=10,fontname=\"Helvetica,Arial,sans-serif\"];
       end
     end
   end
+
+  def self.cr_input_pdhs cr
+    pdhs = []
+    input_obj = cr[:mounts].andand[:"/var/lib/cwl/cwl.input.json"].andand[:content] || cr[:mounts]
+    if input_obj
+      find_collections input_obj do |col_hash, col_uuid, key|
+        if col_hash
+          pdhs << col_hash
+        end
+      end
+    end
+    pdhs
+  end
 end