6429: Tests for priority update propagation to process tree, max priority from
[arvados.git] / services / api / app / models / container_request.rb
1 require 'whitelist_update'
2
3 class ContainerRequest < ArvadosModel
4   include HasUuid
5   include KindAndEtag
6   include CommonApiTemplate
7   include WhitelistUpdate
8
9   serialize :properties, Hash
10   serialize :environment, Hash
11   serialize :mounts, Hash
12   serialize :runtime_constraints, Hash
13   serialize :command, Array
14
15   before_validation :fill_field_defaults, :if => :new_record?
16   before_validation :set_container
17   validates :command, :container_image, :output_path, :cwd, :presence => true
18   validate :validate_change
19   after_save :update_priority
20
21   api_accessible :user, extend: :common do |t|
22     t.add :command
23     t.add :container_count_max
24     t.add :container_image
25     t.add :container_uuid
26     t.add :cwd
27     t.add :description
28     t.add :environment
29     t.add :expires_at
30     t.add :filters
31     t.add :mounts
32     t.add :name
33     t.add :output_path
34     t.add :priority
35     t.add :properties
36     t.add :requesting_container_uuid
37     t.add :runtime_constraints
38     t.add :state
39   end
40
41   # Supported states for a container request
42   States =
43     [
44      (Uncommitted = 'Uncommitted'),
45      (Committed = 'Committed'),
46      (Final = 'Final'),
47     ]
48
49   def skip_uuid_read_permission_check
50     # XXX temporary until permissions are sorted out.
51     %w(modified_by_client_uuid container_uuid requesting_container_uuid)
52   end
53
54   protected
55
56   def fill_field_defaults
57     self.state ||= Uncommitted
58     self.environment ||= {}
59     self.runtime_constraints ||= {}
60     self.mounts ||= {}
61     self.cwd ||= "."
62     self.priority ||= 1
63   end
64
65   def set_container
66     if self.container_uuid_changed?
67       if not current_user.andand.is_admin and not self.container_uuid.nil?
68         errors.add :container_uuid, "Cannot only update container_uuid to nil."
69       end
70     else
71       if self.state_changed?
72         if self.state == Committed and (self.state_was == Uncommitted or self.state_was.nil?)
73           act_as_system_user do
74             self.container_uuid = Container.resolve(self).andand.uuid
75           end
76         end
77       end
78     end
79   end
80
81   def validate_change
82     permitted = [:owner_uuid]
83
84     case self.state
85     when Uncommitted
86       # Permit updating most fields
87       permitted.push :command, :container_count_max,
88                      :container_image, :cwd, :description, :environment,
89                      :filters, :mounts, :name, :output_path, :priority,
90                      :properties, :requesting_container_uuid, :runtime_constraints,
91                      :state, :container_uuid
92
93     when Committed
94       if container_uuid.nil?
95         errors.add :container_uuid, "Has not been resolved to a container."
96       end
97
98       # Can update priority, container count.
99       permitted.push :priority, :container_count_max, :container_uuid
100
101       if self.state_changed?
102         if self.state_was == Uncommitted or self.state_was.nil?
103           # Allow create-and-commit in a single operation.
104           permitted.push :command, :container_image, :cwd, :description, :environment,
105                          :filters, :mounts, :name, :output_path, :properties,
106                          :requesting_container_uuid, :runtime_constraints,
107                          :state, :container_uuid
108         else
109           errors.add :state, "Can only go from Uncommitted to Committed"
110         end
111       end
112
113     when Final
114       if self.state_changed?
115         if self.state_was == Committed
116           permitted.push :state
117         else
118           errors.add :state, "Can only go from Committed to Final"
119         end
120       else
121         errors.add "Cannot update record in Final state"
122       end
123
124     else
125       errors.add :state, "Invalid state #{self.state}"
126     end
127
128     check_update_whitelist permitted
129   end
130
131   def update_priority
132     if self.state == Committed and (self.state_changed? or
133                                     self.priority_changed? or
134                                     self.container_uuid_changed?)
135       c = Container.find_by_uuid self.container_uuid
136       act_as_system_user do
137         c.update_priority!
138       end
139     end
140   end
141
142 end