Merge branch 'explorer'
[arvados.git] / services / api / app / models / pipeline_instance.rb
1 class PipelineInstance < OrvosModel
2   include AssignUuid
3   include KindAndEtag
4   include CommonApiTemplate
5   serialize :components, Hash
6   serialize :properties, Hash
7   belongs_to :pipeline_template, :foreign_key => :pipeline_template_uuid, :primary_key => :uuid
8   attr_accessor :pipeline_template
9
10   before_validation :bootstrap_components
11   before_validation :update_success
12
13   api_accessible :superuser, :extend => :common do |t|
14     t.add :pipeline_template_uuid
15     t.add :pipeline_template, :if => :pipeline_template
16     t.add :name
17     t.add :components
18     t.add :success
19     t.add :active
20     t.add :dependencies
21   end
22
23   def dependencies
24     dependency_search(self.components).keys
25   end
26
27   def progress_table
28     begin
29       # v0 pipeline format
30       nrow = -1
31       components['steps'].collect do |step|
32         nrow += 1
33         row = [nrow, step['name']]
34         if step['complete'] and step['complete'] != 0
35           if step['output_data_locator']
36             row << 1.0
37           else
38             row << 0.0
39           end
40         else
41           row << 0.0
42           if step['failed']
43             self.success = false
44           end
45         end
46         row << (step['warehousejob']['id'] rescue nil)
47         row << (step['warehousejob']['revision'] rescue nil)
48         row << step['output_data_locator']
49         row << (Time.parse(step['warehousejob']['finishtime']) rescue nil)
50         row
51       end
52     rescue
53       []
54     end
55   end
56
57   def progress_ratio
58     t = progress_table
59     return 0 if t.size < 1
60     t.collect { |r| r[2] }.inject(0.0) { |sum,a| sum += a } / t.size
61   end
62
63   protected
64   def bootstrap_components
65     if pipeline_template and (!components or components.empty?)
66       self.components = pipeline_template.components
67     end
68   end
69
70   def update_success
71     if components and progress_ratio == 1.0
72       self.success = true
73     end
74   end
75
76   def dependency_search(haystack)
77     if haystack.is_a? String
78       if (re = haystack.match /^([0-9a-f]{32}(\+[^,]+)*)+/)
79         {re[1] => true}
80       else
81         {}
82       end
83     elsif haystack.is_a? Array
84       deps = {}
85       haystack.each do |value|
86         deps.merge! dependency_search(value)
87       end
88       deps
89     elsif haystack.respond_to? :keys
90       deps = {}
91       haystack.each do |key, value|
92         deps.merge! dependency_search(value)
93       end
94       deps
95     else
96       {}
97     end
98   end
99 end