before_validation :set_timestamps
validates :command, :container_image, :output_path, :cwd, :presence => true
validate :validate_change
+ after_save :request_finalize
+ after_save :process_tree_priority
has_many :container_requests, :foreign_key => :container_uuid, :class_name => 'ContainerRequest', :primary_key => :uuid
(Cancelled = 'Cancelled')
]
+ def self.resolve req
+ 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 })
+ end
+
+ def update_priority!
+ max = 0
+ ContainerRequest.where(container_uuid: uuid).each do |cr|
+ if cr.priority > max
+ max = cr.priority
+ end
+ end
+ self.priority = max
+ self.save!
+ end
+
protected
def fill_field_defaults
check_update_whitelist permitted
end
+ def request_finalize
+ 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 = ContainerRequest.Final
+ cr.save!
+ end
+ end
+ end
+ end
+
+ def process_tree_priority
+ if self.priority_changed?
+ 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
+ end
+ end
+ end
+ end
+
end
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_change
+ after_save :update_priority
api_accessible :user, extend: :common do |t|
t.add :command
self.priority ||= 1
end
+ def set_container
+ if self.state_changed?
+ if self.state == Committed and (self.state_was == Uncommitted or self.state_was.nil?)
+ act_as_system_user do
+ self.container_uuid = Container.resolve(self).andand.uuid
+ Link.create!(head_uuid: self.container_uuid,
+ tail_uuid: self.owner_uuid,
+ link_class: "permission",
+ name: "can_read")
+ end
+ end
+ end
+ end
+
def validate_change
permitted = [:owner_uuid]
: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.
+ # Can update priority, container count.
permitted.push :priority, :container_count_max
if self.state_changed?
- if self.state_was == Uncommitted
- permitted.push :state
+ if self.state_was == Uncommitted or self.state_was.nil?
+ # Allow create-and-commit in a single operation.
+ permitted.push :command, :container_count_max,
+ :container_image, :cwd, :description, :environment,
+ :filters, :mounts, :name, :output_path, :priority,
+ :properties, :requesting_container_uuid, :runtime_constraints,
+ :state, :container_uuid
else
errors.add :state, "Can only go from Uncommitted to Committed"
end
end
- if self.container_uuid_changed? and current_user.andand.is_admin
- permitted.push :container_uuid
- end
-
when Final
if self.state_changed?
if self.state_was == Committed
check_update_whitelist permitted
end
+ def update_priority
+ if self.state == Committed and self.priority_changed?
+ c = Container.find_by_uuid self.container_uuid
+ c.update_priority!
+ end
+ end
+
end
require 'test_helper'
class ContainerRequestTest < ActiveSupport::TestCase
- # test "the truth" do
- # assert true
- # end
+ def check_illegal_modify c
+ assert_raises(ActiveRecord::RecordInvalid) do
+ c.reload
+ c.command = ["echo", "bar"]
+ c.save!
+ end
+
+ assert_raises(ActiveRecord::RecordInvalid) do
+ c.reload
+ c.container_image = "img2"
+ c.save!
+ end
+
+ assert_raises(ActiveRecord::RecordInvalid) do
+ c.reload
+ c.cwd = "/tmp2"
+ c.save!
+ end
+
+ assert_raises(ActiveRecord::RecordInvalid) do
+ c.reload
+ c.environment = {"FOO" => "BAR"}
+ c.save!
+ end
+
+ assert_raises(ActiveRecord::RecordInvalid) do
+ c.reload
+ c.mounts = {"FOO" => "BAR"}
+ c.save!
+ end
+
+ assert_raises(ActiveRecord::RecordInvalid) do
+ c.reload
+ c.output_path = "/tmp3"
+ c.save!
+ end
+
+ assert_raises(ActiveRecord::RecordInvalid) do
+ c.reload
+ c.runtime_constraints = {"FOO" => "BAR"}
+ c.save!
+ end
+
+ assert_raises(ActiveRecord::RecordInvalid) do
+ c.reload
+ c.name = "baz"
+ c.save!
+ end
+
+ assert_raises(ActiveRecord::RecordInvalid) do
+ c.reload
+ c.description = "baz"
+ c.save!
+ end
+
+ end
+
+ def check_bogus_states c
+ assert_raises(ActiveRecord::RecordInvalid) do
+ c.reload
+ c.state = nil
+ c.save!
+ end
+
+ assert_raises(ActiveRecord::RecordInvalid) do
+ c.reload
+ c.state = "Flubber"
+ c.save!
+ end
+ end
+
+ test "Container request create" do
+ set_user_from_auth :active_trustedclient
+ c = ContainerRequest.new
+ c.command = ["echo", "foo"]
+ c.container_image = "img"
+ c.cwd = "/tmp"
+ c.environment = {}
+ c.mounts = {"BAR" => "FOO"}
+ c.output_path = "/tmp"
+ c.priority = 1
+ c.runtime_constraints = {}
+ c.name = "foo"
+ c.description = "bar"
+ c.save!
+
+ assert_nil c.container_uuid
+
+ check_bogus_states c
+
+ c.reload
+ c.command = ["echo", "foo3"]
+ c.container_image = "img3"
+ c.cwd = "/tmp3"
+ c.environment = {"BUP" => "BOP"}
+ c.mounts = {"BAR" => "BAZ"}
+ c.output_path = "/tmp4"
+ c.priority = 2
+ c.runtime_constraints = {"X" => "Y"}
+ c.name = "foo3"
+ c.description = "bar3"
+ c.save!
+
+ assert_nil c.container_uuid
+ end
+
+ test "Container request commit" do
+ set_user_from_auth :active_trustedclient
+ c = ContainerRequest.new
+ c.command = ["echo", "foo"]
+ c.container_image = "img"
+ c.cwd = "/tmp"
+ c.environment = {}
+ c.mounts = {"BAR" => "FOO"}
+ c.output_path = "/tmp"
+ c.priority = 1
+ c.runtime_constraints = {}
+ c.name = "foo"
+ c.description = "bar"
+ c.save!
+
+ c.reload
+ assert_nil c.container_uuid
+
+ c.reload
+ c.state = "Committed"
+ c.save!
+
+ c.reload
+
+ t = Container.find_by_uuid c.container_uuid
+ assert_equal c.command, t.command
+ assert_equal c.container_image, t.container_image
+ assert_equal c.cwd, t.cwd
+ end
+
+
end