add script/dispatch_jobs.rb and related Job features
[arvados.git] / app / models / job.rb
1 class Job < OrvosModel
2   include AssignUuid
3   include KindAndEtag
4   include CommonApiTemplate
5   serialize :command_parameters, Hash
6   serialize :tasks_summary, Hash
7   before_create :ensure_unique_submit_id
8
9   class SubmitIdReused < StandardError
10   end
11
12   api_accessible :superuser, :extend => :common do |t|
13     t.add :submit_id
14     t.add :priority
15     t.add :command
16     t.add :command_parameters
17     t.add :command_version
18     t.add :cancelled_at
19     t.add :cancelled_by_client
20     t.add :cancelled_by_user
21     t.add :started_at
22     t.add :finished_at
23     t.add :success
24     t.add :running
25     t.add :is_locked_by
26     t.add :log
27     t.add :tasks_summary
28     t.add :dependencies
29   end
30
31   def assert_finished
32     update_attributes(finished_at: finished_at || Time.now,
33                       success: success.nil? ? false : success,
34                       running: false)
35   end
36
37   protected
38
39   def ensure_unique_submit_id
40     if !submit_id.nil?
41       if Job.where('submit_id=?',self.submit_id).first
42         raise SubmitIdReused.new
43       end
44     end
45     true
46   end
47
48   def dependencies
49     deps = {}
50     self.command_parameters.values.each do |v|
51       v.match(/^(([0-9a-f]{32})\b(\+[^,]+)?,?)*$/) do |locator|
52         bare_locator = locator[0].gsub(/\+[^,]+/,'')
53         deps[bare_locator] = true
54       end
55     end
56     deps.keys
57   end
58
59   def permission_to_update
60     if is_locked_by_was and !(current_user and
61                               current_user.uuid == is_locked_by_was)
62       if command_changed? or
63           command_parameters_changed? or
64           command_version_changed? or
65           cancelled_by_client_changed? or
66           cancelled_by_user_changed? or
67           cancelled_at_changed? or
68           started_at_changed? or
69           finished_at_changed? or
70           running_changed? or
71           success_changed? or
72           output_changed? or
73           log_changed? or
74           tasks_summary_changed?
75         logger.warn "User #{current_user.uuid if current_user} tried to change protected job attributes on locked #{self.class.to_s} #{uuid_was}"
76         return false
77       end
78     end
79     if !is_locked_by_changed?
80       super
81     else
82       if !current_user
83         logger.warn "Anonymous user tried to change lock on #{self.class.to_s} #{uuid_was}"
84         false
85       elsif is_locked_by_was and is_locked_by_was != current_user.uuid
86         logger.warn "User #{current_user.uuid} tried to steal lock on #{self.class.to_s} #{uuid_was} from #{is_locked_by_was}"
87         false
88       elsif !is_locked_by.nil? and is_locked_by != current_user.uuid
89         logger.warn "User #{current_user.uuid} tried to lock #{self.class.to_s} #{uuid_was} with uuid #{is_locked_by}"
90         false
91       else
92         super
93       end
94     end
95   end
96 end