From 2f27547b2ec374fddbaed63b2a72362d7bf81157 Mon Sep 17 00:00:00 2001 From: Tom Clegg Date: Thu, 4 Aug 2016 01:48:33 -0400 Subject: [PATCH] 9595: Support "json" mount type. --- sdk/go/arvados/container.go | 13 +++--- services/crunch-run/crunchrun.go | 62 +++++++++++++++++++-------- services/crunch-run/crunchrun_test.go | 22 ++++++++++ 3 files changed, 72 insertions(+), 25 deletions(-) diff --git a/sdk/go/arvados/container.go b/sdk/go/arvados/container.go index ac129526fd..bb36b17324 100644 --- a/sdk/go/arvados/container.go +++ b/sdk/go/arvados/container.go @@ -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, diff --git a/services/crunch-run/crunchrun.go b/services/crunch-run/crunchrun.go index 32d524abca..060a4625cf 100644 --- a/services/crunch-run/crunchrun.go +++ b/services/crunch-run/crunchrun.go @@ -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)) } } diff --git a/services/crunch-run/crunchrun_test.go b/services/crunch-run/crunchrun_test.go index d95ff08631..36e83a43df 100644 --- a/services/crunch-run/crunchrun_test.go +++ b/services/crunch-run/crunchrun_test.go @@ -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) { -- 2.30.2