X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/b29ca38e4409fe0149aea28a0e26a84d56ccca17..397981dadc145225c691c8643b10527c9710f1fb:/apps/workbench/app/helpers/provenance_helper.rb diff --git a/apps/workbench/app/helpers/provenance_helper.rb b/apps/workbench/app/helpers/provenance_helper.rb index 3567cbaee6..cef5cc7ee8 100644 --- a/apps/workbench/app/helpers/provenance_helper.rb +++ b/apps/workbench/app/helpers/provenance_helper.rb @@ -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