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 :request_finalize
- after_save :process_tree_priority
+ after_save :handle_completed
has_many :container_requests, :foreign_key => :container_uuid, :class_name => 'ContainerRequest', :primary_key => :uuid
(Cancelled = 'Cancelled')
]
- # Turn a container request into a container.
- def self.resolve req
- # In the future this will do things like resolve symbolic git and keep
- # references to content addresses.
- Container.create!({ :command => req.command,
- :container_image => req.container_image,
- :cwd => req.cwd,
- :environment => req.environment,
- :mounts => req.mounts,
- :output_path => req.output_path,
- :runtime_constraints => req.runtime_constraints })
+ State_transitions = {
+ nil => [Queued],
+ Queued => [Running, Cancelled],
+ Running => [Complete, Cancelled]
+ }
+
+ def state_transitions
+ State_transitions
end
def update_priority!
- # 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 == "Committed" and cr.priority > max
- max = cr.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
- self.priority = max
- self.save!
end
protected
# permit priority change only.
permitted.push :priority
- if self.state_changed? and not self.state_was.nil?
- errors.add :state, "Can only go to from nil to Queued"
- end
-
when Running
if self.state_changed?
# At point of state change, can 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
-
+ permitted.push :state, :started_at
+ else
# While running, can update priority and progress.
permitted.push :priority, :progress
end
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 request_finalize
+ 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
- ContainerRequest.where(container_uuid: uuid).each do |cr|
- cr.state = "Final"
- cr.save!
+ # 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
- end
- end
- end
- def process_tree_priority
- if self.priority_changed?
- # This could propagate any parent priority to the children (not just
- # priority 0)
- if self.priority == 0
- act_as_system_user do
- ContainerRequest.where(requesting_container_uuid: uuid).each do |cr|
- cr.priority = self.priority
- 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