before_validation :fill_field_defaults, :if => :new_record?
before_validation :set_timestamps
- validates :command, :container_image, :output_path, :cwd, :presence => true
+ validates :command, :container_image, :output_path, :cwd, :priority, :presence => true
+ validate :validate_state_change
validate :validate_change
+ after_save :handle_completed
has_many :container_requests, :foreign_key => :container_uuid, :class_name => 'ContainerRequest', :primary_key => :uuid
(Cancelled = 'Cancelled')
]
+ State_transitions = {
+ nil => [Queued],
+ Queued => [Running, Cancelled],
+ Running => [Complete, Cancelled]
+ }
+
+ def state_transitions
+ State_transitions
+ end
+
+ def update_priority!
+ if [Queued, Running].include? self.state
+ # Update the priority of this container to the maximum priority of any of
+ # its committed container requests and save the record.
+ max = 0
+ ContainerRequest.where(container_uuid: uuid).each do |cr|
+ if cr.state == ContainerRequest::Committed and cr.priority > max
+ max = cr.priority
+ end
+ end
+ self.priority = max
+ self.save!
+ end
+ end
+
protected
def fill_field_defaults
# permit priority change only.
permitted.push :priority
- if self.state_changed? and not self.state_was.nil?
- errors.add :state, "Can only go to Queued from nil"
- end
-
when Running
if self.state_changed?
- # At point of state change, can only set state and started_at
- if self.state_was == Queued
- permitted.push :state, :started_at
- else
- errors.add :state, "Can only go from Queued to Running"
- end
+ # At point of state change, can set state and started_at
+ permitted.push :state, :started_at
else
# While running, can update priority and progress.
permitted.push :priority, :progress
when Complete
if self.state_changed?
- if self.state_was == Running
- permitted.push :state, :finished_at, :output, :log
- else
- errors.add :state, "Cannot go from #{self.state_was} to #{self.state}"
- end
+ permitted.push :state, :finished_at, :output, :log
else
- errors.add :state, "Cannot update record in Complete state"
+ errors.add :state, "cannot update record"
end
when Cancelled
permitted.push :state, :finished_at, :output, :log
elsif self.state_was == Queued
permitted.push :state, :finished_at
- else
- errors.add :state, "Cannot go from #{self.state_was} to #{self.state}"
end
else
- errors.add :state, "Cannot update record in Cancelled state"
+ errors.add :state, "cannot update record"
end
else
- errors.add :state, "Invalid state #{self.state}"
+ errors.add :state, "invalid state"
end
check_update_whitelist permitted
end
+ def handle_completed
+ # This container is finished so finalize any associated container requests
+ # that are associated with this container.
+ if self.state_changed? and [Complete, Cancelled].include? self.state
+ act_as_system_user do
+ # Try to close container requests associated with this container
+ ContainerRequest.where(container_uuid: uuid,
+ :state => ContainerRequest::Committed).each do |cr|
+ cr.state = ContainerRequest::Final
+ cr.save
+ end
+
+ # Try to cancel any outstanding container requests made by this container.
+ ContainerRequest.where(requesting_container_uuid: uuid,
+ :state => ContainerRequest::Committed).each do |cr|
+ cr.priority = 0
+ cr.save
+ end
+ end
+ end
+ end
+
end