9595: Support "json" mount type.
authorTom Clegg <tom@curoverse.com>
Thu, 4 Aug 2016 05:48:33 +0000 (01:48 -0400)
committerTom Clegg <tom@curoverse.com>
Thu, 4 Aug 2016 05:48:33 +0000 (01:48 -0400)
sdk/go/arvados/container.go
services/crunch-run/crunchrun.go
services/crunch-run/crunchrun_test.go

index ac129526fdda23652e0b7f351c9a9b89c9c6f088..bb36b17324ce06c808e25dd5fe83901f094dae1d 100644 (file)
@@ -18,12 +18,13 @@ type Container struct {
 
 // Mount is special behavior to attach to a filesystem path or device.
 type Mount struct {
-       Kind             string `json:"kind"`
-       Writable         bool   `json:"writable"`
-       PortableDataHash string `json:"portable_data_hash"`
-       UUID             string `json:"uuid"`
-       DeviceType       string `json:"device_type"`
-       Path             string `json:"path"`
+       Kind             string      `json:"kind"`
+       Writable         bool        `json:"writable"`
+       PortableDataHash string      `json:"portable_data_hash"`
+       UUID             string      `json:"uuid"`
+       DeviceType       string      `json:"device_type"`
+       Path             string      `json:"path"`
+       Content          interface{} `json:"content"`
 }
 
 // RuntimeConstraints specify a container's compute resources (RAM,
index 32d524abca2f59689e56efe59b526d9da8f37181..060a4625cf810f89c3f100433ce88aa5f45ba2cc 100644 (file)
@@ -18,6 +18,7 @@ import (
        "os/exec"
        "os/signal"
        "path"
+       "path/filepath"
        "strings"
        "sync"
        "syscall"
@@ -255,7 +256,8 @@ func (runner *ContainerRunner) SetupMounts() (err error) {
                        }
                }
 
-               if mnt.Kind == "collection" {
+               switch {
+               case mnt.Kind == "collection":
                        var src string
                        if mnt.UUID != "" && mnt.PortableDataHash != "" {
                                return fmt.Errorf("Cannot specify both 'uuid' and 'portable_data_hash' for a collection mount")
@@ -286,25 +288,47 @@ func (runner *ContainerRunner) SetupMounts() (err error) {
                                runner.Binds = append(runner.Binds, fmt.Sprintf("%s:%s:ro", src, bind))
                        }
                        collectionPaths = append(collectionPaths, src)
-               } else if mnt.Kind == "tmp" {
-                       if bind == runner.Container.OutputPath {
-                               runner.HostOutputDir, err = runner.MkTempDir("", "")
-                               if err != nil {
-                                       return fmt.Errorf("While creating mount temp dir: %v", err)
-                               }
-                               st, staterr := os.Stat(runner.HostOutputDir)
-                               if staterr != nil {
-                                       return fmt.Errorf("While Stat on temp dir: %v", staterr)
-                               }
-                               err = os.Chmod(runner.HostOutputDir, st.Mode()|os.ModeSetgid|0777)
-                               if staterr != nil {
-                                       return fmt.Errorf("While Chmod temp dir: %v", err)
-                               }
-                               runner.CleanupTempDir = append(runner.CleanupTempDir, runner.HostOutputDir)
-                               runner.Binds = append(runner.Binds, fmt.Sprintf("%s:%s", runner.HostOutputDir, bind))
-                       } else {
-                               runner.Binds = append(runner.Binds, bind)
+
+               case mnt.Kind == "tmp" && bind == runner.Container.OutputPath:
+                       runner.HostOutputDir, err = runner.MkTempDir("", "")
+                       if err != nil {
+                               return fmt.Errorf("While creating mount temp dir: %v", err)
+                       }
+                       st, staterr := os.Stat(runner.HostOutputDir)
+                       if staterr != nil {
+                               return fmt.Errorf("While Stat on temp dir: %v", staterr)
+                       }
+                       err = os.Chmod(runner.HostOutputDir, st.Mode()|os.ModeSetgid|0777)
+                       if staterr != nil {
+                               return fmt.Errorf("While Chmod temp dir: %v", err)
+                       }
+                       runner.CleanupTempDir = append(runner.CleanupTempDir, runner.HostOutputDir)
+                       runner.Binds = append(runner.Binds, fmt.Sprintf("%s:%s", runner.HostOutputDir, bind))
+
+               case mnt.Kind == "tmp":
+                       runner.Binds = append(runner.Binds, bind)
+
+               case mnt.Kind == "json":
+                       jsondata, err := json.Marshal(mnt.Content)
+                       if err != nil {
+                               return fmt.Errorf("encoding json data: %v", err)
+                       }
+                       // Create a tempdir with a single file
+                       // (instead of just a tempfile): this way we
+                       // can ensure the file is world-readable
+                       // inside the container, without having to
+                       // make it world-readable on the docker host.
+                       tmpdir, err := runner.MkTempDir("", "")
+                       if err != nil {
+                               return fmt.Errorf("creating temp dir: %v", err)
+                       }
+                       runner.CleanupTempDir = append(runner.CleanupTempDir, tmpdir)
+                       tmpfn := filepath.Join(tmpdir, "mountdata.json")
+                       err = ioutil.WriteFile(tmpfn, jsondata, 0644)
+                       if err != nil {
+                               return fmt.Errorf("writing temp file: %v", err)
                        }
+                       runner.Binds = append(runner.Binds, fmt.Sprintf("%s:%s:ro", tmpfn, bind))
                }
        }
 
index d95ff086312c4552e534f9e0ca9803e85e053231..36e83a43df00ab5756f23788121d2d745e1c4483 100644 (file)
@@ -807,6 +807,28 @@ func (s *TestSuite) TestSetupMounts(c *C) {
                        "/tmp/mktmpdir1/tmp0:/keepout"})
                cr.CleanupDirs()
        }
+
+       for _, test := range []struct {
+               in  interface{}
+               out string
+       }{
+               {in: "foo", out: `"foo"`},
+               {in: nil, out: `null`},
+               {in: map[string]int{"foo": 123}, out: `{"foo":123}`},
+       } {
+               i = 0
+               cr.Container.Mounts = map[string]arvados.Mount{
+                       "/mnt/test.json": {Kind: "json", Content: test.in},
+               }
+               err := cr.SetupMounts()
+               c.Check(err, IsNil)
+               sort.StringSlice(cr.Binds).Sort()
+               c.Check(cr.Binds, DeepEquals, []string{"/tmp/mktmpdir2/mountdata.json:/mnt/test.json:ro"})
+               content, err := ioutil.ReadFile("/tmp/mktmpdir2/mountdata.json")
+               c.Check(err, IsNil)
+               c.Check(content, DeepEquals, []byte(test.out))
+               cr.CleanupDirs()
+       }
 }
 
 func (s *TestSuite) TestStdout(c *C) {