Merge branch 'master' into 10231-keep-cache-runtime-constraints
authorradhika <radhika@curoverse.com>
Mon, 31 Oct 2016 16:04:51 +0000 (12:04 -0400)
committerradhika <radhika@curoverse.com>
Mon, 31 Oct 2016 16:04:51 +0000 (12:04 -0400)
1  2 
sdk/cwl/arvados_cwl/arvcontainer.py
services/api/test/unit/container_request_test.rb
services/crunch-run/crunchrun.go
services/crunch-run/crunchrun_test.go

index ed843477449554612597a1b6d1d6e6d0da4523fb,1581d20d2f62920a5259fe936248900966947ccb..c2029b965b4f3b5173bcd981a67ff8bf3c809d3d
@@@ -97,7 -97,7 +97,7 @@@ class ArvadosContainer(object)
  
          runtime_req, _ = get_feature(self, "http://arvados.org/cwl#RuntimeConstraints")
          if runtime_req:
 -            logger.warn("RuntimeConstraints not yet supported by container API")
 +            runtime_constraints["keep_cache_ram"] = runtime_req["keep_cache"]
  
          partition_req, _ = get_feature(self, "http://arvados.org/cwl#PartitionRequirement")
          if partition_req:
  
              self.arvrunner.processes[response["container_uuid"]] = self
  
-             logger.info("Container %s (%s) request state is %s", self.name, response["uuid"], response["state"])
+             container = self.arvrunner.api.containers().get(
+                 uuid=response["container_uuid"]
+             ).execute(num_retries=self.arvrunner.num_retries)
+             logger.info("Container request %s (%s) state is %s with container %s %s", self.name, response["uuid"], response["state"], container["uuid"], container["state"])
  
-             if response["state"] == "Final":
-                 self.done(response)
+             if container["state"] in ("Complete", "Cancelled"):
+                 self.done(container)
          except Exception as e:
              logger.error("Got error %s" % str(e))
              self.output_callback({}, "permanentFail")
index 172ba4986660916d2a29ba1193e9a53d27b6496c,406bb42d1290c6f00b55421a695fac1813154245..b2b0d57df56f9fec8a899e4c2eb6edb53027cc24
@@@ -276,7 -276,7 +276,7 @@@ class ContainerRequestTest < ActiveSupp
    end
  
    [
-     ['active', 'zzzzz-dz642-runningcontainr'],
+     ['running_container_auth', 'zzzzz-dz642-runningcontainr'],
      ['active_no_prefs', nil],
    ].each do |token, expected|
      test "create as #{token} and expect requesting_container_uuid to be #{expected}" do
                        command: ["echo", "hello"],
                        output_path: "test",
                        runtime_constraints: {"vcpus" => 4,
 -                                            "ram" => 12000000000},
 +                                            "ram" => 12000000000,
 +                                            "keep_cache_ram" => 268435456},
                        mounts: {"test" => {"kind" => "json"}}}
        set_user_from_auth :active
        cr1 = create_minimal_req!(common_attrs.merge({state: ContainerRequest::Committed,
      assert_equal cr.container_uuid, cr3.container_uuid
      assert_equal ContainerRequest::Final, cr3.state
    end
 +
 +  [
 +    [{"vcpus" => 1, "ram" => 123, "keep_cache_ram" => 100}, ContainerRequest::Committed, 100],
 +    [{"vcpus" => 1, "ram" => 123}, ContainerRequest::Uncommitted],
 +    [{"vcpus" => 1, "ram" => 123}, ContainerRequest::Committed],
 +    [{"vcpus" => 1, "ram" => 123, "keep_cache_ram" => -1}, ContainerRequest::Committed, ActiveRecord::RecordInvalid],
 +    [{"vcpus" => 1, "ram" => 123, "keep_cache_ram" => '123'}, ContainerRequest::Committed, ActiveRecord::RecordInvalid],
 +  ].each do |rc, state, expected|
 +    test "create container request with #{rc} in state #{state} and verify keep_cache_ram #{expected}" do
 +      common_attrs = {cwd: "test",
 +                      priority: 1,
 +                      command: ["echo", "hello"],
 +                      output_path: "test",
 +                      runtime_constraints: rc,
 +                      mounts: {"test" => {"kind" => "json"}}}
 +      set_user_from_auth :active
 +
 +      if expected == ActiveRecord::RecordInvalid
 +        assert_raises(ActiveRecord::RecordInvalid) do
 +          create_minimal_req!(common_attrs.merge({state: state}))
 +        end
 +      else
 +        cr = create_minimal_req!(common_attrs.merge({state: state}))
 +        expected = Rails.configuration.container_default_keep_cache_ram if state == ContainerRequest::Committed and expected.nil?
 +        assert_equal expected, cr.runtime_constraints['keep_cache_ram']
 +      end
 +    end
 +  end
  end
index ab3a9f524e68d137bf2ba371e2f8ba6a34e0ae21,0b59a3bb78c1b0c8919f198f5c34cc94ed00d5a9..8e5cdb1f3b20ef1fbd9ef6114689148d12f0e781
@@@ -357,10 -357,6 +357,10 @@@ func (runner *ContainerRunner) SetupMou
        }
        arvMountCmd = append(arvMountCmd, runner.ArvMountPoint)
  
 +      if runner.Container.RuntimeConstraints.KeepCacheRAM > 0 {
 +              arvMountCmd = append(arvMountCmd, "--file-cache", fmt.Sprintf("%d", runner.Container.RuntimeConstraints.KeepCacheRAM))
 +      }
 +
        token, err := runner.ContainerToken()
        if err != nil {
                return fmt.Errorf("could not get container token: %s", err)
@@@ -567,6 -563,21 +567,21 @@@ func (runner *ContainerRunner) CaptureO
                return nil
        }
  
+       if wantAPI := runner.Container.RuntimeConstraints.API; wantAPI != nil && *wantAPI {
+               // Output may have been set directly by the container, so
+               // refresh the container record to check.
+               err := runner.ArvClient.Get("containers", runner.Container.UUID,
+                       nil, &runner.Container)
+               if err != nil {
+                       return err
+               }
+               if runner.Container.Output != "" {
+                       // Container output is already set.
+                       runner.OutputPDH = &runner.Container.Output
+                       return nil
+               }
+       }
        if runner.HostOutputDir == "" {
                return nil
        }
index 7ac71cc486a92baf91464764bba69bd3a38da674,7f8e80cb107296b4184dfad5c1c76f9a29585c92..2fbbb4db97da2be13eeb5f4f37bc31ed2fb61c09
@@@ -69,6 -69,7 +69,7 @@@ type TestDockerClient struct 
        stop        chan bool
        cwd         string
        env         []string
+       api         *ArvTestClient
  }
  
  func NewTestDockerClient() *TestDockerClient {
@@@ -527,6 -528,7 +528,7 @@@ func FullRunHelper(c *C, record string
        docker.RemoveImage(hwImageId, true)
  
        api = &ArvTestClient{Container: rec}
+       docker.api = api
        cr = NewContainerRunner(api, &KeepTestClient{}, docker, "zzzzz-zzzzz-zzzzzzzzzzzzzzz")
        cr.statInterval = 100 * time.Millisecond
        am := &ArvMountCmdLine{}
@@@ -835,28 -837,6 +837,28 @@@ func (s *TestSuite) TestSetupMounts(c *
                c.Check(am.Cmd, DeepEquals, []string{"--foreground", "--allow-other", "--read-write", "--mount-tmp", "tmp0", "--mount-by-pdh", "by_id", realTemp + "/keep1"})
                sort.StringSlice(cr.Binds).Sort()
                c.Check(cr.Binds, DeepEquals, []string{realTemp + "/keep1/by_id/59389a8f9ee9d399be35462a0f92541c+53:/keepinp:ro",
 +                      realTemp + "/keep1/tmp0:/keepout"})
 +              cr.CleanupDirs()
 +              checkEmpty()
 +      }
 +
 +      {
 +              i = 0
 +              cr.Container.RuntimeConstraints.KeepCacheRAM = 512
 +              cr.Container.Mounts = map[string]arvados.Mount{
 +                      "/keepinp": {Kind: "collection", PortableDataHash: "59389a8f9ee9d399be35462a0f92541c+53"},
 +                      "/keepout": {Kind: "collection", Writable: true},
 +              }
 +              cr.OutputPath = "/keepout"
 +
 +              os.MkdirAll(realTemp+"/keep1/by_id/59389a8f9ee9d399be35462a0f92541c+53", os.ModePerm)
 +              os.MkdirAll(realTemp+"/keep1/tmp0", os.ModePerm)
 +
 +              err := cr.SetupMounts()
 +              c.Check(err, IsNil)
 +              c.Check(am.Cmd, DeepEquals, []string{"--foreground", "--allow-other", "--read-write", "--mount-tmp", "tmp0", "--mount-by-pdh", "by_id", realTemp + "/keep1", "--file-cache", "512"})
 +              sort.StringSlice(cr.Binds).Sort()
 +              c.Check(cr.Binds, DeepEquals, []string{realTemp + "/keep1/by_id/59389a8f9ee9d399be35462a0f92541c+53:/keepinp:ro",
                        realTemp + "/keep1/tmp0:/keepout"})
                cr.CleanupDirs()
                checkEmpty()
@@@ -957,3 -937,50 +959,50 @@@ func (s *TestSuite) TestStdoutWithWrong
        c.Check(err, NotNil)
        c.Check(strings.Contains(err.Error(), "Unsupported mount kind 'collection' for stdout"), Equals, true)
  }
+ func (s *TestSuite) TestFullRunWithAPI(c *C) {
+       os.Setenv("ARVADOS_API_HOST", "test.arvados.org")
+       defer os.Unsetenv("ARVADOS_API_HOST")
+       api, _ := FullRunHelper(c, `{
+     "command": ["/bin/sh", "-c", "echo $ARVADOS_API_HOST"],
+     "container_image": "d4ab34d3d4f8a72f5c4973051ae69fab+122",
+     "cwd": "/bin",
+     "environment": {},
+     "mounts": {"/tmp": {"kind": "tmp"} },
+     "output_path": "/tmp",
+     "priority": 1,
+     "runtime_constraints": {"API": true}
+ }`, func(t *TestDockerClient) {
+               t.logWriter.Write(dockerLog(1, t.env[1][17:]+"\n"))
+               t.logWriter.Close()
+               t.finish <- dockerclient.WaitResult{ExitCode: 0}
+       })
+       c.Check(api.CalledWith("container.exit_code", 0), NotNil)
+       c.Check(api.CalledWith("container.state", "Complete"), NotNil)
+       c.Check(strings.HasSuffix(api.Logs["stdout"].String(), "test.arvados.org\n"), Equals, true)
+       c.Check(api.CalledWith("container.output", "d41d8cd98f00b204e9800998ecf8427e+0"), NotNil)
+ }
+ func (s *TestSuite) TestFullRunSetOutput(c *C) {
+       os.Setenv("ARVADOS_API_HOST", "test.arvados.org")
+       defer os.Unsetenv("ARVADOS_API_HOST")
+       api, _ := FullRunHelper(c, `{
+     "command": ["/bin/sh", "-c", "echo $ARVADOS_API_HOST"],
+     "container_image": "d4ab34d3d4f8a72f5c4973051ae69fab+122",
+     "cwd": "/bin",
+     "environment": {},
+     "mounts": {"/tmp": {"kind": "tmp"} },
+     "output_path": "/tmp",
+     "priority": 1,
+     "runtime_constraints": {"API": true}
+ }`, func(t *TestDockerClient) {
+               t.api.Container.Output = "d4ab34d3d4f8a72f5c4973051ae69fab+122"
+               t.logWriter.Close()
+               t.finish <- dockerclient.WaitResult{ExitCode: 0}
+       })
+       c.Check(api.CalledWith("container.exit_code", 0), NotNil)
+       c.Check(api.CalledWith("container.state", "Complete"), NotNil)
+       c.Check(api.CalledWith("container.output", "d4ab34d3d4f8a72f5c4973051ae69fab+122"), NotNil)
+ }