6429: Rename request_finalize to handle_completed
[arvados.git] / services / api / app / models / container.rb
index 4d1908f69e5c822e6ea9a231cd2e60839f716762..d777c0c2fe1e81148a0345fec8e71895cb403d01 100644 (file)
@@ -13,8 +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 :handle_completed
 
   has_many :container_requests, :foreign_key => :container_uuid, :class_name => 'ContainerRequest', :primary_key => :uuid
 
@@ -44,6 +46,31 @@ class Container < ArvadosModel
      (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
@@ -86,18 +113,10 @@ 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 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
@@ -105,13 +124,9 @@ class Container < ArvadosModel
 
     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
@@ -120,18 +135,38 @@ 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 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