6429: Rename request_finalize to handle_completed
[arvados.git] / services / api / app / models / container.rb
index f452b10a2dc64b514d01659836344ce84ff366de..d777c0c2fe1e81148a0345fec8e71895cb403d01 100644 (file)
@@ -13,10 +13,10 @@ class Container < ArvadosModel
 
   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
 
@@ -46,30 +46,29 @@ class Container < ArvadosModel
      (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
@@ -114,32 +113,20 @@ class Container < ArvadosModel
       # 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
@@ -148,41 +135,35 @@ class Container < ArvadosModel
           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