Working on state change assertions and testing for container record.
[arvados.git] / services / api / app / models / container_request.rb
1 class ContainerRequest < ArvadosModel
2   include HasUuid
3   include KindAndEtag
4   include CommonApiTemplate
5
6   serialize :properties, Hash
7   serialize :environment, Hash
8   serialize :mounts, Hash
9   serialize :runtime_constraints, Hash
10   serialize :command, Array
11
12   before_create :set_state_before_save
13   validate :validate_change_permitted
14   validate :validate_status
15   validate :validate_state_change
16
17   api_accessible :user, extend: :common do |t|
18     t.add :command
19     t.add :container_count_max
20     t.add :container_image
21     t.add :container_uuid
22     t.add :cwd
23     t.add :description
24     t.add :environment
25     t.add :expires_at
26     t.add :filters
27     t.add :mounts
28     t.add :name
29     t.add :output_path
30     t.add :priority
31     t.add :properties
32     t.add :requesting_container_uuid
33     t.add :runtime_constraints
34     t.add :state
35   end
36
37   # Supported states for a container request
38   States =
39     [
40      (Uncommitted = 'Uncommitted'),
41      (Committed = 'Committed'),
42      (Final = 'Final'),
43     ]
44
45   def set_state_before_save
46     self.state ||= Uncommitted
47   end
48
49   def validate_change_permitted
50     if self.changed?
51       ok = case self.state
52            when nil
53              true
54            when Uncommitted
55              true
56            when Committed
57              # only allow state and priority to change.
58              not (self.command_changed? or
59                   self.container_count_max_changed? or
60                   self.container_image_changed? or
61                   self.container_uuid_changed? or
62                   self.cwd_changed? or
63                   self.description_changed? or
64                   self.environment_changed? or
65                   self.expires_at_changed? or
66                   self.filters_changed? or
67                   self.mounts_changed? or
68                   self.name_changed? or
69                   self.output_path_changed? or
70                   self.properties_changed? or
71                   self.requesting_container_uuid_changed? or
72                   self.runtime_constraints_changed?)
73            when Final
74              false
75            else
76              false
77            end
78       if not ok
79         errors.add :state, "Invalid update of container request in #{self.state} state"
80       end
81     end
82   end
83
84   def validate_status
85     if self.state.in?(States)
86       true
87     else
88       errors.add :state, "#{state.inspect} must be one of: #{States.inspect}"
89       false
90     end
91   end
92
93   def validate_state_change
94     ok = true
95     if self.state_changed?
96       ok = case self.state_was
97            when nil
98              # Must go to Uncommitted
99              self.state == Uncommitted
100            when Uncommitted
101              # Must go to Committed
102              self.state == Committed
103            when Committed
104              # Must to go Final
105              self.state == Final
106            when Final
107              # Once in a final state, don't permit any more state changes
108              false
109            else
110              # Any other state transition is also invalid
111              false
112            end
113       if not ok
114         errors.add :state, "invalid change from #{self.state_was} to #{self.state}"
115       end
116     end
117     ok
118   end
119
120
121 end