4d1908f69e5c822e6ea9a231cd2e60839f716762
[arvados.git] / services / api / app / models / container.rb
1 require 'whitelist_update'
2
3 class Container < ArvadosModel
4   include HasUuid
5   include KindAndEtag
6   include CommonApiTemplate
7   include WhitelistUpdate
8
9   serialize :environment, Hash
10   serialize :mounts, Hash
11   serialize :runtime_constraints, Hash
12   serialize :command, Array
13
14   before_validation :fill_field_defaults, :if => :new_record?
15   before_validation :set_timestamps
16   validates :command, :container_image, :output_path, :cwd, :presence => true
17   validate :validate_change
18
19   has_many :container_requests, :foreign_key => :container_uuid, :class_name => 'ContainerRequest', :primary_key => :uuid
20
21   api_accessible :user, extend: :common do |t|
22     t.add :command
23     t.add :container_image
24     t.add :cwd
25     t.add :environment
26     t.add :finished_at
27     t.add :log
28     t.add :mounts
29     t.add :output
30     t.add :output_path
31     t.add :priority
32     t.add :progress
33     t.add :runtime_constraints
34     t.add :started_at
35     t.add :state
36   end
37
38   # Supported states for a container
39   States =
40     [
41      (Queued = 'Queued'),
42      (Running = 'Running'),
43      (Complete = 'Complete'),
44      (Cancelled = 'Cancelled')
45     ]
46
47   protected
48
49   def fill_field_defaults
50     self.state ||= Queued
51     self.environment ||= {}
52     self.runtime_constraints ||= {}
53     self.mounts ||= {}
54     self.cwd ||= "."
55     self.priority ||= 1
56   end
57
58   def permission_to_create
59     current_user.andand.is_admin
60   end
61
62   def permission_to_update
63     current_user.andand.is_admin
64   end
65
66   def set_timestamps
67     if self.state_changed? and self.state == Running
68       self.started_at ||= db_current_time
69     end
70
71     if self.state_changed? and [Complete, Cancelled].include? self.state
72       self.finished_at ||= db_current_time
73     end
74   end
75
76   def validate_change
77     permitted = []
78
79     if self.new_record?
80       permitted.push :owner_uuid, :command, :container_image, :cwd, :environment,
81                      :mounts, :output_path, :priority, :runtime_constraints, :state
82     end
83
84     case self.state
85     when Queued
86       # permit priority change only.
87       permitted.push :priority
88
89       if self.state_changed? and not self.state_was.nil?
90         errors.add :state, "Can only go to Queued from nil"
91       end
92
93     when Running
94       if self.state_changed?
95         # At point of state change, can only set state and started_at
96         if self.state_was == Queued
97           permitted.push :state, :started_at
98         else
99           errors.add :state, "Can only go from Queued to Running"
100         end
101       else
102         # While running, can update priority and progress.
103         permitted.push :priority, :progress
104       end
105
106     when Complete
107       if self.state_changed?
108         if self.state_was == Running
109           permitted.push :state, :finished_at, :output, :log
110         else
111           errors.add :state, "Cannot go from #{self.state_was} to #{self.state}"
112         end
113       else
114         errors.add :state, "Cannot update record in Complete state"
115       end
116
117     when Cancelled
118       if self.state_changed?
119         if self.state_was == Running
120           permitted.push :state, :finished_at, :output, :log
121         elsif self.state_was == Queued
122           permitted.push :state, :finished_at
123         else
124           errors.add :state, "Cannot go from #{self.state_was} to #{self.state}"
125         end
126       else
127         errors.add :state, "Cannot update record in Cancelled state"
128       end
129
130     else
131       errors.add :state, "Invalid state #{self.state}"
132     end
133
134     check_update_whitelist permitted
135   end
136
137 end