X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/5044c03a66e63b3e1fe4e0fdeec4a3f77fed0310..3ede205bf0e5af7a88e04009cd66ff111e0729c3:/services/api/app/models/container_request.rb diff --git a/services/api/app/models/container_request.rb b/services/api/app/models/container_request.rb index aaebcd3b90..6353132e90 100644 --- a/services/api/app/models/container_request.rb +++ b/services/api/app/models/container_request.rb @@ -13,8 +13,11 @@ class ContainerRequest < ArvadosModel serialize :command, Array before_validation :fill_field_defaults, :if => :new_record? + before_validation :set_container validates :command, :container_image, :output_path, :cwd, :presence => true + validate :validate_state_change validate :validate_change + after_save :update_priority api_accessible :user, extend: :common do |t| t.add :command @@ -44,6 +47,27 @@ class ContainerRequest < ArvadosModel (Final = 'Final'), ] + State_transitions = { + nil => [Uncommitted, Committed], + Uncommitted => [Committed], + Committed => [Final] + } + + def state_transitions + State_transitions + end + + def skip_uuid_read_permission_check + # XXX temporary until permissions are sorted out. + %w(modified_by_client_uuid container_uuid requesting_container_uuid) + end + + def container_completed! + # may implement retry logic here in the future. + self.state = ContainerRequest::Final + self.save! + end + protected def fill_field_defaults @@ -52,7 +76,35 @@ class ContainerRequest < ArvadosModel self.runtime_constraints ||= {} self.mounts ||= {} self.cwd ||= "." - self.priority ||= 1 + end + + # Create a new container (or find an existing one) to satisfy this + # request. + def resolve + # TODO: resolve symbolic git and keep references to content + # addresses. + c = act_as_system_user do + Container.create!(command: self.command, + container_image: self.container_image, + cwd: self.cwd, + environment: self.environment, + mounts: self.mounts, + output_path: self.output_path, + runtime_constraints: self.runtime_constraints) + end + self.container_uuid = c.uuid + end + + def set_container + if (container_uuid_changed? and + not current_user.andand.is_admin and + not container_uuid.nil?) + errors.add :container_uuid, "can only be updated to nil." + return false + end + if state_changed? and state == Committed and container_uuid.nil? + resolve + end end def validate_change @@ -65,44 +117,57 @@ class ContainerRequest < ArvadosModel :container_image, :cwd, :description, :environment, :filters, :mounts, :name, :output_path, :priority, :properties, :requesting_container_uuid, :runtime_constraints, - :state + :state, :container_uuid - if self.container_uuid_changed? and (current_user.andand.is_admin or self.container_uuid.nil?) - permitted.push :container_uuid + when Committed + if container_uuid.nil? + errors.add :container_uuid, "has not been resolved to a container." end - when Committed - # Can only update priority, container count. - permitted.push :priority, :container_count_max + if priority.nil? + errors.add :priority, "cannot be nil" + end + + # Can update priority, container count. + permitted.push :priority, :container_count_max, :container_uuid if self.state_changed? - if self.state_was == Uncommitted - permitted.push :state - else - errors.add :state, "Can only go from Uncommitted to Committed" - end + # Allow create-and-commit in a single operation. + permitted.push :command, :container_image, :cwd, :description, :environment, + :filters, :mounts, :name, :output_path, :properties, + :requesting_container_uuid, :runtime_constraints, + :state, :container_uuid end - if self.container_uuid_changed? and current_user.andand.is_admin - permitted.push :container_uuid + when Final + if not current_user.andand.is_admin + errors.add :state, "of container request can only be set to Final by system." end - when Final if self.state_changed? - if self.state_was == Committed permitted.push :state - else - errors.add :state, "Can only go from Committed to Final" - end else - errors.add "Cannot update record in Final state" + errors.add :state, "does not allow updates" end else - errors.add :state, "Invalid state #{self.state}" + errors.add :state, "invalid value" end check_update_whitelist permitted end + def update_priority + if self.state_changed? or + self.priority_changed? or + self.container_uuid_changed? + act_as_system_user do + Container. + where('uuid in (?)', + [self.container_uuid_was, self.container_uuid].compact). + map(&:update_priority!) + end + end + end + end