[ARVADOS] updated: be4ca15acae878c7f8c45979996cf31abc83fcdd
Git user
git at public.curoverse.com
Fri Jun 24 13:57:07 EDT 2016
Summary of changes:
services/api/app/models/container_request.rb | 51 +++-
services/api/test/unit/container_request_test.rb | 335 ++++++++++-------------
2 files changed, 190 insertions(+), 196 deletions(-)
via be4ca15acae878c7f8c45979996cf31abc83fcdd (commit)
via 873f98c1b28bb816209a7f6cb4a3e765e6c687e3 (commit)
via 7490d5fd83b70a5f705e9b3de797d02fece024cc (commit)
from e3c6b307c9aa963c22457cd42eed41047d4c72c9 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
commit be4ca15acae878c7f8c45979996cf31abc83fcdd
Author: Tom Clegg <tom at curoverse.com>
Date: Fri Jun 24 13:55:08 2016 -0400
8470: Resolve docker image hash or tag to collection PDH when creating a Container.
diff --git a/services/api/app/models/container_request.rb b/services/api/app/models/container_request.rb
index 6e758f6..80f05a6 100644
--- a/services/api/app/models/container_request.rb
+++ b/services/api/app/models/container_request.rb
@@ -85,9 +85,10 @@ class ContainerRequest < ArvadosModel
# TODO: resolve container_image to a content address.
c_mounts = mounts_for_container
c_runtime_constraints = runtime_constraints_for_container
+ c_container_image = container_image_for_container
c = act_as_system_user do
Container.create!(command: self.command,
- container_image: self.container_image,
+ container_image: c_container_image,
cwd: self.cwd,
environment: self.environment,
mounts: c_mounts,
@@ -149,6 +150,15 @@ class ContainerRequest < ArvadosModel
return c_mounts
end
+ # Return a container_image PDH suitable for a Container.
+ def container_image_for_container
+ coll = Collection.for_latest_docker_image(container_image)
+ if !coll
+ raise ActiveRecord::RecordNotFound.new "docker image #{container_image.inspect} not found"
+ end
+ return coll.portable_data_hash
+ end
+
def set_container
if (container_uuid_changed? and
not current_user.andand.is_admin and
diff --git a/services/api/test/unit/container_request_test.rb b/services/api/test/unit/container_request_test.rb
index de15961..3347f87 100644
--- a/services/api/test/unit/container_request_test.rb
+++ b/services/api/test/unit/container_request_test.rb
@@ -4,7 +4,7 @@ class ContainerRequestTest < ActiveSupport::TestCase
def create_minimal_req! attrs={}
defaults = {
command: ["echo", "foo"],
- container_image: "img",
+ container_image: links(:docker_image_collection_tag).name,
cwd: "/tmp",
environment: {},
mounts: {"/out" => {"kind" => "tmp", "capacity" => 1000000}},
@@ -79,7 +79,7 @@ class ContainerRequestTest < ActiveSupport::TestCase
c = Container.find_by_uuid cr.container_uuid
assert_not_nil c
assert_equal ["echo", "foo"], c.command
- assert_equal "img", c.container_image
+ assert_equal collections(:docker_image).portable_data_hash, c.container_image
assert_equal "/tmp", c.cwd
assert_equal({}, c.environment)
assert_equal({"/out" => {"kind"=>"tmp", "capacity"=>1000000}}, c.mounts)
@@ -191,7 +191,7 @@ class ContainerRequestTest < ActiveSupport::TestCase
set_user_from_auth :active
cr = ContainerRequest.new
cr.state = "Committed"
- cr.container_image = "img"
+ cr.container_image = "arvados/apitestfixture"
cr.command = ["foo", "bar"]
cr.output_path = "/tmp"
cr.cwd = "/tmp"
@@ -203,7 +203,7 @@ class ContainerRequestTest < ActiveSupport::TestCase
cr2 = ContainerRequest.new
cr2.state = "Committed"
- cr2.container_image = "img"
+ cr2.container_image = "arvados/apitestfixture"
cr2.command = ["foo", "bar"]
cr2.output_path = "/tmp"
cr2.cwd = "/tmp"
@@ -324,4 +324,37 @@ class ContainerRequestTest < ActiveSupport::TestCase
cr.send :mounts_for_container
end
end
+
+ ['arvados/apitestfixture:latest',
+ 'arvados/apitestfixture',
+ 'd8309758b8fe2c81034ffc8a10c36460b77db7bc5e7b448c4e5b684f9d95a678',
+ ].each do |tag|
+ test "container_image_for_container(#{tag.inspect})" do
+ set_user_from_auth :active
+ cr = ContainerRequest.new(container_image: tag)
+ resolved = cr.send :container_image_for_container
+ assert_equal resolved, collections(:docker_image).portable_data_hash
+ end
+ end
+
+ test "container_image_for_container(pdh)" do
+ set_user_from_auth :active
+ pdh = collections(:docker_image).portable_data_hash
+ cr = ContainerRequest.new(container_image: pdh)
+ resolved = cr.send :container_image_for_container
+ assert_equal resolved, pdh
+ end
+
+ ['acbd18db4cc2f85cedef654fccc4a4d8+3',
+ 'ENOEXIST',
+ 'arvados/apitestfixture:ENOEXIST',
+ ].each do |img|
+ test "container_image_for_container(#{img.inspect}) => 404" do
+ set_user_from_auth :active
+ cr = ContainerRequest.new(container_image: img)
+ assert_raises(ActiveRecord::RecordNotFound) do
+ cr.send :container_image_for_container
+ end
+ end
+ end
end
commit 873f98c1b28bb816209a7f6cb4a3e765e6c687e3
Author: Tom Clegg <tom at curoverse.com>
Date: Thu Jun 23 22:28:50 2016 -0400
8470: Clean up ContainerRequest tests.
diff --git a/services/api/test/unit/container_request_test.rb b/services/api/test/unit/container_request_test.rb
index f2964f8..de15961 100644
--- a/services/api/test/unit/container_request_test.rb
+++ b/services/api/test/unit/container_request_test.rb
@@ -9,7 +9,6 @@ class ContainerRequestTest < ActiveSupport::TestCase
environment: {},
mounts: {"/out" => {"kind" => "tmp", "capacity" => 1000000}},
output_path: "/out",
- priority: 1,
runtime_constraints: {},
name: "foo",
description: "bar",
@@ -19,97 +18,26 @@ class ContainerRequestTest < ActiveSupport::TestCase
return cr
end
- def check_illegal_modify c
+ def check_bogus_states cr
+ [nil, "Flubber"].each do |state|
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!
+ cr.state = state
+ cr.save!
end
+ cr.reload
+ end
end
test "Container request create" do
- set_user_from_auth :active_trustedclient
- cr = ContainerRequest.new
- cr.command = ["echo", "foo"]
- cr.container_image = "img"
- cr.cwd = "/tmp"
- cr.environment = {}
- cr.mounts = {"BAR" => "FOO"}
- cr.output_path = "/tmpout"
- cr.runtime_constraints = {}
- cr.name = "foo"
- cr.description = "bar"
- cr.save!
+ set_user_from_auth :active
+ cr = create_minimal_req!
assert_nil cr.container_uuid
assert_nil cr.priority
check_bogus_states cr
- cr.reload
+ # Ensure we can modify all attributes
cr.command = ["echo", "foo3"]
cr.container_image = "img3"
cr.cwd = "/tmp3"
@@ -117,7 +45,7 @@ class ContainerRequestTest < ActiveSupport::TestCase
cr.mounts = {"BAR" => "BAZ"}
cr.output_path = "/tmp4"
cr.priority = 2
- cr.runtime_constraints = {"X" => "Y"}
+ cr.runtime_constraints = {"vcpus" => 4}
cr.name = "foo3"
cr.description = "bar3"
cr.save!
@@ -142,6 +70,7 @@ class ContainerRequestTest < ActiveSupport::TestCase
cr.reload
cr.state = "Committed"
+ cr.priority = 1
cr.save!
cr.reload
@@ -170,160 +99,96 @@ class ContainerRequestTest < ActiveSupport::TestCase
c.reload
assert_equal 0, cr.priority
assert_equal 0, c.priority
-
end
test "Container request max priority" do
- set_user_from_auth :active_trustedclient
- cr = ContainerRequest.new
- cr.state = "Committed"
- cr.container_image = "img"
- cr.command = ["foo", "bar"]
- cr.output_path = "/tmp"
- cr.cwd = "/tmp"
- cr.priority = 5
- cr.save!
+ set_user_from_auth :active
+ cr = create_minimal_req!(priority: 5, state: "Committed")
c = Container.find_by_uuid cr.container_uuid
assert_equal 5, c.priority
- cr2 = ContainerRequest.new
- cr2.container_image = "img"
- cr2.command = ["foo", "bar"]
- cr2.output_path = "/tmp"
- cr2.cwd = "/tmp"
+ cr2 = create_minimal_req!
cr2.priority = 10
- cr2.save!
-
+ cr2.state = "Committed"
+ cr2.container_uuid = cr.container_uuid
act_as_system_user do
- cr2.state = "Committed"
- cr2.container_uuid = cr.container_uuid
cr2.save!
end
c.reload
assert_equal 10, c.priority
- cr2.reload
- cr2.priority = 0
- cr2.save!
+ cr2.update_attributes!(priority: 0)
c.reload
assert_equal 5, c.priority
- cr.reload
- cr.priority = 0
- cr.save!
+ cr.update_attributes!(priority: 0)
c.reload
assert_equal 0, c.priority
-
end
test "Independent container requests" do
- set_user_from_auth :active_trustedclient
- cr = ContainerRequest.new
- cr.state = "Committed"
- cr.container_image = "img"
- cr.command = ["foo", "bar"]
- cr.output_path = "/tmp"
- cr.cwd = "/tmp"
- cr.priority = 5
- cr.save!
-
- cr2 = ContainerRequest.new
- cr2.state = "Committed"
- cr2.container_image = "img"
- cr2.command = ["foo", "bar"]
- cr2.output_path = "/tmp"
- cr2.cwd = "/tmp"
- cr2.priority = 10
- cr2.save!
+ set_user_from_auth :active
+ cr1 = create_minimal_req!(command: ["foo", "1"], priority: 5, state: "Committed")
+ cr2 = create_minimal_req!(command: ["foo", "2"], priority: 10, state: "Committed")
- c = Container.find_by_uuid cr.container_uuid
- assert_equal 5, c.priority
+ c1 = Container.find_by_uuid cr1.container_uuid
+ assert_equal 5, c1.priority
c2 = Container.find_by_uuid cr2.container_uuid
assert_equal 10, c2.priority
- cr.priority = 0
- cr.save!
+ cr1.update_attributes!(priority: 0)
- c.reload
- assert_equal 0, c.priority
+ c1.reload
+ assert_equal 0, c1.priority
c2.reload
assert_equal 10, c2.priority
end
-
test "Container cancelled finalizes request" do
- set_user_from_auth :active_trustedclient
- cr = ContainerRequest.new
- cr.state = "Committed"
- cr.container_image = "img"
- cr.command = ["foo", "bar"]
- cr.output_path = "/tmp"
- cr.cwd = "/tmp"
- cr.priority = 5
- cr.save!
-
- cr.reload
- assert_equal "Committed", cr.state
-
- c = Container.find_by_uuid cr.container_uuid
- assert_equal "Queued", c.state
+ set_user_from_auth :active
+ cr = create_minimal_req!(priority: 1, state: "Committed")
act_as_system_user do
- c.state = "Cancelled"
- c.save!
+ Container.find_by_uuid(cr.container_uuid).
+ update_attributes!(state: Container::Cancelled)
end
cr.reload
assert_equal "Final", cr.state
-
end
-
test "Container complete finalizes request" do
- set_user_from_auth :active_trustedclient
- cr = ContainerRequest.new
- cr.state = "Committed"
- cr.container_image = "img"
- cr.command = ["foo", "bar"]
- cr.output_path = "/tmp"
- cr.cwd = "/tmp"
- cr.priority = 5
- cr.save!
-
- cr.reload
- assert_equal "Committed", cr.state
-
- c = Container.find_by_uuid cr.container_uuid
- assert_equal Container::Queued, c.state
+ set_user_from_auth :active
+ cr = create_minimal_req!(priority: 1, state: "Committed")
- act_as_system_user do
- c.update_attributes! state: Container::Locked
- c.update_attributes! state: Container::Running
+ c = act_as_system_user do
+ c = Container.find_by_uuid(cr.container_uuid)
+ c.update_attributes!(state: Container::Locked)
+ c.update_attributes!(state: Container::Running)
+ c
end
cr.reload
assert_equal "Committed", cr.state
act_as_system_user do
- c.update_attributes! state: Container::Complete
- c.save!
+ c.update_attributes!(state: Container::Complete)
end
cr.reload
assert_equal "Final", cr.state
-
end
test "Container makes container request, then is cancelled" do
- set_user_from_auth :active_trustedclient
+ set_user_from_auth :active
cr = ContainerRequest.new
cr.state = "Committed"
cr.container_image = "img"
commit 7490d5fd83b70a5f705e9b3de797d02fece024cc
Author: Tom Clegg <tom at curoverse.com>
Date: Thu Jun 23 21:42:51 2016 -0400
8470: Resolve mounts to PDH.
diff --git a/services/api/app/models/container_request.rb b/services/api/app/models/container_request.rb
index 221da0d..6e758f6 100644
--- a/services/api/app/models/container_request.rb
+++ b/services/api/app/models/container_request.rb
@@ -82,15 +82,17 @@ class ContainerRequest < ArvadosModel
# Create a new container (or find an existing one) to satisfy this
# request.
def resolve
- # TODO: resolve mounts and container_image to content addresses.
+ # TODO: resolve container_image to a content address.
+ c_mounts = mounts_for_container
+ c_runtime_constraints = runtime_constraints_for_container
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,
+ mounts: c_mounts,
output_path: self.output_path,
- runtime_constraints: runtime_constraints_for_container)
+ runtime_constraints: c_runtime_constraints)
end
self.container_uuid = c.uuid
end
@@ -116,6 +118,37 @@ class ContainerRequest < ArvadosModel
rc
end
+ # Return a mounts hash suitable for a Container, i.e., with every
+ # readonly collection UUID resolved to a PDH.
+ def mounts_for_container
+ c_mounts = {}
+ mounts.each do |k, mount|
+ mount = mount.dup
+ c_mounts[k] = mount
+ if mount['kind'] != 'collection'
+ next
+ end
+ if (uuid = mount.delete 'uuid')
+ c = Collection.
+ readable_by(current_user).
+ where(uuid: uuid).
+ select(:portable_data_hash).
+ first
+ if !c
+ raise ActiveRecord::RecordNotFound.new "collection #{uuid} not found"
+ end
+ if mount['portable_data_hash'].nil?
+ # PDH not supplied by client
+ mount['portable_data_hash'] = c.portable_data_hash
+ elsif mount['portable_data_hash'] != c.portable_data_hash
+ # UUID and PDH supplied by client, but they don't agree
+ raise ArgumentError.new "uuid #{uuid} has portable_data_hash #{c.portable_data_hash}, not #{c['portable_data_hash']}"
+ end
+ end
+ end
+ return c_mounts
+ end
+
def set_container
if (container_uuid_changed? and
not current_user.andand.is_admin and
diff --git a/services/api/test/unit/container_request_test.rb b/services/api/test/unit/container_request_test.rb
index f510f25..f2964f8 100644
--- a/services/api/test/unit/container_request_test.rb
+++ b/services/api/test/unit/container_request_test.rb
@@ -126,20 +126,8 @@ class ContainerRequestTest < ActiveSupport::TestCase
end
test "Container request priority must be non-nil" do
- set_user_from_auth :active_trustedclient
- cr = ContainerRequest.new
- cr.command = ["echo", "foo"]
- cr.container_image = "img"
- cr.cwd = "/tmp"
- cr.environment = {}
- cr.mounts = {"BAR" => "FOO"}
- cr.output_path = "/tmpout"
- cr.runtime_constraints = {}
- cr.name = "foo"
- cr.description = "bar"
- cr.save!
-
- cr.reload
+ set_user_from_auth :active
+ cr = create_minimal_req!(priority: nil)
cr.state = "Committed"
assert_raises(ActiveRecord::RecordInvalid) do
cr.save!
@@ -406,4 +394,69 @@ class ContainerRequestTest < ActiveSupport::TestCase
"container runtime_constraints was #{resolved.inspect}")
end
end
+
+ [[{"/out" => {"kind" => "collection", "uuid" => "zzzzz-4zz18-znfnqtbbv4spc3w", "path" => "/foo"}},
+ lambda do |resolved|
+ resolved["/out"] == {
+ "portable_data_hash" => "1f4b0bc7583c2a7f9102c395f4ffc5e3+45",
+ "kind" => "collection",
+ "path" => "/foo",
+ }
+ end],
+ ].each do |mounts, okfunc|
+ test "resolve runtime constraint range #{mounts} to values" do
+ set_user_from_auth :active
+ cr = ContainerRequest.new(mounts: mounts)
+ resolved = cr.send :mounts_for_container
+ assert(okfunc.call(resolved),
+ "mounts_for_container returned #{resolved.inspect}")
+ end
+ end
+
+ test 'mount unreadable collection' do
+ set_user_from_auth :spectator
+ m = {
+ "/foo" => {
+ "kind" => "collection",
+ "uuid" => "zzzzz-4zz18-znfnqtbbv4spc3w",
+ "path" => "/foo",
+ },
+ }
+ cr = ContainerRequest.new(mounts: m)
+ assert_raises(ActiveRecord::RecordNotFound) do
+ cr.send :mounts_for_container
+ end
+ end
+
+ test 'mount collection with matching UUID and PDH' do
+ set_user_from_auth :active
+ m = {
+ "/foo" => {
+ "kind" => "collection",
+ "uuid" => "zzzzz-4zz18-znfnqtbbv4spc3w",
+ "portable_data_hash" => "1f4b0bc7583c2a7f9102c395f4ffc5e3+45",
+ "path" => "/foo",
+ },
+ }
+ cr = ContainerRequest.new(mounts: m)
+ resolved = cr.send :mounts_for_container
+ assert_equal "1f4b0bc7583c2a7f9102c395f4ffc5e3+45", resolved["/foo"]["portable_data_hash"]
+ refute_includes resolved["/foo"], "uuid"
+ end
+
+ test 'mount collection with mismatched UUID and PDH' do
+ set_user_from_auth :active
+ m = {
+ "/foo" => {
+ "kind" => "collection",
+ "uuid" => "zzzzz-4zz18-znfnqtbbv4spc3w",
+ "portable_data_hash" => "fa7aeb5140e2848d39b416daeef4ffc5+45",
+ "path" => "/foo",
+ },
+ }
+ cr = ContainerRequest.new(mounts: m)
+ assert_raises(ArgumentError) do
+ cr.send :mounts_for_container
+ end
+ end
end
-----------------------------------------------------------------------
hooks/post-receive
--
More information about the arvados-commits
mailing list