[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