[ARVADOS] updated: 1.1.2-85-ge509c5f

Git user git at public.curoverse.com
Sat Jan 13 15:12:47 EST 2018


Summary of changes:
 build/run-build-docker-jobs-image.sh               |  20 +-
 build/run-build-packages-one-target.sh             |   5 +-
 build/run-library.sh                               |   9 +-
 build/run-tests.sh                                 |  32 +-
 doc/_config.yml                                    |   3 +
 doc/admin/change-account-owner.html.textile.liquid |  41 ++
 doc/admin/merge-remote-account.html.textile.liquid |  45 ++
 doc/api/methods/users.html.textile.liquid          |  13 +
 .../install-slurm.html.textile.liquid              |   2 +
 lib/cli/external.go                                |  25 +
 lib/cmd/cmd.go                                     |  13 +-
 lib/mount/command.go                               |  28 +-
 lib/mount/command_test.go                          |  59 ++
 lib/mount/fs.go                                    |   7 +
 lib/mount/fs_test.go                               |  40 +-
 sdk/cwl/arvados_cwl/arvworkflow.py                 |   9 +-
 sdk/cwl/arvados_cwl/runner.py                      |  15 +-
 sdk/cwl/tests/arvados-tests.yml                    |  11 +
 .../cwl/tests/secondary/dir/hg19.fa                |   0
 .../cwl/tests/secondary/dir/hg19.fa.amb            |   0
 .../cwl/tests/secondary/dir/hg19.fa.ann            |   0
 .../cwl/tests/secondary/dir/hg19.fa.fai            |   0
 sdk/cwl/tests/secondary/ls.cwl                     |  11 +
 sdk/cwl/tests/secondary/sub.cwl                    |  17 +
 sdk/cwl/tests/secondary/wf-job.yml                 |   3 +
 sdk/cwl/tests/secondary/wf.cwl                     |  23 +
 .../wf/{runin-wf.cwl => runin-with-ttl-wf.cwl}     |  11 +-
 sdk/go/arvados/fs_base.go                          |  51 +-
 sdk/go/arvados/fs_site.go                          |  13 +-
 sdk/go/arvados/fs_site_test.go                     |  21 +
 sdk/go/arvados/node.go                             |  44 ++
 .../app/controllers/arvados/v1/users_controller.rb |  17 +-
 services/api/app/models/user.rb                    |  26 +
 services/api/config/routes.rb                      |   1 +
 .../test/fixtures/api_client_authorizations.yml    |   8 +-
 services/api/test/fixtures/containers.yml          |   3 +-
 .../functional/arvados/v1/users_controller_test.rb |  21 +
 services/api/test/unit/container_test.rb           |   2 +-
 services/api/test/unit/user_test.rb                |  79 +++
 services/arv-git-httpd/arvados-git-httpd.service   |   9 +-
 .../crunch-dispatch-slurm.service                  |   9 +-
 services/crunch-run/crunchrun.go                   |  96 ++-
 services/crunch-run/crunchrun_test.go              |  39 +-
 services/crunch-run/git_mount.go                   |   7 +-
 services/crunch-run/logging.go                     |   6 +-
 .../dockercleaner/arvados-docker-cleaner.service   |   9 +-
 services/fuse/arvados_fuse/__init__.py             |   5 +-
 services/fuse/tests/test_inodes.py                 |   2 +-
 services/health/arvados-health.service             |  27 +
 services/keep-balance/keep-balance.service         |   9 +-
 services/keep-web/keep-web.service                 |   9 +-
 services/keepproxy/keepproxy.service               |   9 +-
 services/keepproxy/keepproxy_test.go               |  12 +-
 services/keepstore/handler_test.go                 |   2 +-
 services/keepstore/keepstore.service               |   9 +-
 services/ws/arvados-ws.service                     |   9 +-
 tools/arvbox/bin/arvbox                            |   4 +-
 tools/arvbox/lib/arvbox/docker/Dockerfile.base     |  11 +-
 tools/arvbox/lib/arvbox/docker/common.sh           |   7 +-
 tools/arvbox/lib/arvbox/docker/runit/1             |   7 +
 tools/arvbox/lib/arvbox/docker/runit/2             |  10 +
 tools/arvbox/lib/arvbox/docker/runit/3             |  14 +
 tools/arvbox/lib/arvbox/docker/runit/ctrlaltdel    |  13 +
 tools/arvbox/lib/arvbox/docker/service/docker/run  |  10 +-
 .../lib/arvbox/docker/service/ready/run-service    |   3 -
 .../arvbox/lib/arvbox/docker/service/workbench/run |   4 +-
 vendor/vendor.json                                 | 742 ++++++++++++++++-----
 67 files changed, 1507 insertions(+), 314 deletions(-)
 create mode 100644 doc/admin/change-account-owner.html.textile.liquid
 create mode 100644 doc/admin/merge-remote-account.html.textile.liquid
 create mode 100644 lib/mount/command_test.go
 copy tools/crunchstat-summary/tests/__init__.py => sdk/cwl/tests/secondary/dir/hg19.fa (100%)
 copy tools/crunchstat-summary/tests/__init__.py => sdk/cwl/tests/secondary/dir/hg19.fa.amb (100%)
 copy tools/crunchstat-summary/tests/__init__.py => sdk/cwl/tests/secondary/dir/hg19.fa.ann (100%)
 copy tools/crunchstat-summary/tests/__init__.py => sdk/cwl/tests/secondary/dir/hg19.fa.fai (100%)
 create mode 100644 sdk/cwl/tests/secondary/ls.cwl
 create mode 100644 sdk/cwl/tests/secondary/sub.cwl
 create mode 100644 sdk/cwl/tests/secondary/wf-job.yml
 create mode 100644 sdk/cwl/tests/secondary/wf.cwl
 copy sdk/cwl/tests/wf/{runin-wf.cwl => runin-with-ttl-wf.cwl} (91%)
 create mode 100644 sdk/go/arvados/node.go
 create mode 100644 services/health/arvados-health.service
 create mode 100755 tools/arvbox/lib/arvbox/docker/runit/1
 create mode 100755 tools/arvbox/lib/arvbox/docker/runit/2
 create mode 100755 tools/arvbox/lib/arvbox/docker/runit/3
 create mode 100755 tools/arvbox/lib/arvbox/docker/runit/ctrlaltdel

       via  e509c5f6c1c9f9b212705da401713d49c9f78a71 (commit)
       via  e585fcd60cdc0bf9f846e22241af7043364c9e47 (commit)
       via  c549ff8ad5a98d5f12f5081881fcb4e1ae392c1c (commit)
       via  707e31dad5efed2bb4af7e624f90cff80b6e4052 (commit)
       via  d309809f4f81c4f92b7441a0e4dc1e9e2f27be76 (commit)
       via  453f922b16ffa246b32700ce06bf16a1cdffce60 (commit)
       via  813f5f4aad5da71c4fcfe6639c9010e1056acf1f (commit)
       via  cf849fa29c00bf46d7bd5712c00763632f4daecd (commit)
       via  5469772c43759b8bde77c3d78450658e266b9cf0 (commit)
       via  79309a1e149b8d3e62810a32769de30e71be7688 (commit)
       via  8e4fe3e615430ed48631ce15bd3ba3b0864ab03e (commit)
       via  99bc798d924e267cb71d5176fd6cde1edfe9b344 (commit)
       via  94b8d1c4a4152a0b0f1cd531d396eb49e738d6c7 (commit)
       via  e128fc5885c553c9e9b55f2529d0ea6937e5a6b7 (commit)
       via  7bfb9fd099ada6b7466ec3531caebbd5ac0970ba (commit)
       via  1c355040b77161f02a2e351fe7ec32b1d1907ee8 (commit)
       via  56a8f4d0f1ccd871de5fdbb6204ef157e0dd455f (commit)
       via  5e8428f48dd64e48b5dcfd13341c0a6bd44e4d74 (commit)
       via  3cca12f9fb5452831a826964656f48e427d8edcd (commit)
       via  b5a8d7052ff461073496627aef8e2e0c29901a19 (commit)
       via  9bb723068bdba79d9bc6272697c353cac5fda40d (commit)
       via  9f842eecf59f293fd800ece28be2730ff3a39487 (commit)
       via  9e74f69b3ae6abbbc497c8fd2adeef41c96de251 (commit)
       via  2a3daf14afb93de4d65108019a7a1d35aa1052ad (commit)
       via  ee03454bfec20bfb3b743bbd79ccd73f20301f00 (commit)
       via  27ae43f3b4d700a1a35db514130fb17824ae9c80 (commit)
       via  680ffd64dac92aec8ad94454334db9ae69b95b56 (commit)
       via  13d6ff884079f23613c0592cfead88cc92e0bbb3 (commit)
       via  cf8c09785fece3f454af5bc012c5143e44c9342b (commit)
       via  4726a67ad33df26cb84ee9bf4fca6c774ab7ced2 (commit)
       via  4ad076c659f9245494aa46609fa7741dd94c94a9 (commit)
       via  4b9a74f8ce269ebd19b8cfa77c7ebb74df125429 (commit)
       via  a5da28efdbc8d9f2673a1b200a14297447b04664 (commit)
       via  b9851a978e1a1deb8853f7cd5b02acf7c55a24c8 (commit)
       via  02001807b3a68526f3f1a5de9f4cc87e59993b2a (commit)
       via  3d8da9e64df7c0dd0302b7d2f4d188a9ede9099c (commit)
       via  8467390d785c59b4ab219e901ba3df63baf788e8 (commit)
       via  8f8a0ac695f4440412de0245fc748c2792cb1496 (commit)
       via  cda0f329a1210b23fda9cd9fefc52ae925adb3cf (commit)
       via  cd9b6605e5ad6fb90c531fb4f1c98e113f0498ba (commit)
       via  7bc8466abceb800872bb6f687111f9ebe526e141 (commit)
       via  086b27a27c844178ee52a9c4186d970689147628 (commit)
       via  eae6972da6ffbf73d31fd47138cb49c13fed77de (commit)
       via  87647b5d3d72ae0c291fcdf1ee3b4a46b3af91c0 (commit)
       via  456b1c4ef6229c15d80f704647a396da7819139b (commit)
       via  6ac835d8869876955d85a86a4b6d35c12b0d63ac (commit)
       via  13273a566ce37e8426cb851e464ace152d4f02df (commit)
       via  4749f9394bacea3782c701b9bc98f2b9e4995a73 (commit)
       via  987457b7e545f4ad1e32c7a07c00c29c24326421 (commit)
       via  cf5e73998da0cac4a00d29f6004ea58d11c7acd4 (commit)
       via  08fcef34fae00ecb34d34d4d34dbbb2cec98ced8 (commit)
      from  f805036cee9d8316b609fa4d73b46d3e1a14ab16 (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 e509c5f6c1c9f9b212705da401713d49c9f78a71
Author: Tom Clegg <tclegg at veritasgenetics.com>
Date:   Sat Jan 13 15:09:40 2018 -0500

    12308: Improve deadlock prevention. Prevent unsupported renames.
    
    Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tclegg at veritasgenetics.com>

diff --git a/sdk/go/arvados/fs_base.go b/sdk/go/arvados/fs_base.go
index fd8c18b..6402a8e 100644
--- a/sdk/go/arvados/fs_base.go
+++ b/sdk/go/arvados/fs_base.go
@@ -53,6 +53,10 @@ type FileSystem interface {
 
 	rootnode() inode
 
+	// filesystem-wide lock: used by Rename() to prevent deadlock
+	// while locking multiple inodes.
+	locker() sync.Locker
+
 	// create a new node with nil parent.
 	newNode(name string, perm os.FileMode, modTime time.Time) (node inode, err error)
 
@@ -272,12 +276,17 @@ func (n *treenode) Readdir() (fi []os.FileInfo) {
 type fileSystem struct {
 	root inode
 	fsBackend
+	mutex sync.Mutex
 }
 
 func (fs *fileSystem) rootnode() inode {
 	return fs.root
 }
 
+func (fs *fileSystem) locker() sync.Locker {
+	return &fs.mutex
+}
+
 // OpenFile is analogous to os.OpenFile().
 func (fs *fileSystem) OpenFile(name string, flag int, perm os.FileMode) (File, error) {
 	return fs.openFile(name, flag, perm)
@@ -424,12 +433,31 @@ func (fs *fileSystem) Rename(oldname, newname string) error {
 	}
 	defer newdirf.Close()
 
-	// When acquiring locks on multiple nodes, all common
-	// ancestors must be locked first in order to avoid
-	// deadlock. This is assured by locking the path from
-	// filesystem root to newdir, then locking the path from
-	// filesystem root to olddir, skipping any already-locked
-	// nodes.
+	// TODO: If the nearest common ancestor ("nca") of olddirf and
+	// newdirf is on a different filesystem than fs, we should
+	// call nca.FS().Rename() instead of proceeding. Until then
+	// it's awkward for filesystems to implement their own Rename
+	// methods effectively: the only one that runs is the one on
+	// the root filesystem exposed to the caller (webdav, fuse,
+	// etc).
+
+	// When acquiring locks on multiple inodes, avoid deadlock by
+	// locking the entire containing filesystem first.
+	cfs := olddirf.inode.FS()
+	cfs.locker().Lock()
+	defer cfs.locker().Unlock()
+
+	if cfs != newdirf.inode.FS() {
+		// Moving inodes across filesystems is not (yet)
+		// supported. Locking inodes from different
+		// filesystems could deadlock, so we must error out
+		// now.
+		return ErrInvalidArgument
+	}
+
+	// To ensure we can test reliably whether we're about to move
+	// a directory into itself, lock all potential common
+	// ancestors of olddir and newdir.
 	needLock := []sync.Locker{}
 	for _, node := range []inode{olddirf.inode, newdirf.inode} {
 		needLock = append(needLock, node)
@@ -447,8 +475,11 @@ func (fs *fileSystem) Rename(oldname, newname string) error {
 		}
 	}
 
-	err = nil
+	// Return ErrInvalidOperation if olddirf.inode doesn't even
+	// bother calling our "remove oldname entry" replacer func.
+	err = ErrInvalidArgument
 	olddirf.inode.Child(oldname, func(oldinode inode) inode {
+		err = nil
 		if oldinode == nil {
 			err = os.ErrNotExist
 			return nil
@@ -458,6 +489,12 @@ func (fs *fileSystem) Rename(oldname, newname string) error {
 			err = ErrInvalidArgument
 			return oldinode
 		}
+		if oldinode.FS() != cfs && newdirf.inode != olddirf.inode {
+			// moving a mount point to a different parent
+			// is not (yet) supported.
+			err = ErrInvalidArgument
+			return oldinode
+		}
 		accepted := newdirf.inode.Child(newname, func(existing inode) inode {
 			if existing != nil && existing.IsDir() {
 				err = ErrIsDirectory
diff --git a/sdk/go/arvados/fs_site.go b/sdk/go/arvados/fs_site.go
index d3ca510..9f3dbce 100644
--- a/sdk/go/arvados/fs_site.go
+++ b/sdk/go/arvados/fs_site.go
@@ -20,13 +20,16 @@ type siteFileSystem struct {
 // there are significant known bugs and shortcomings. For example,
 // writes are not persisted until Sync() is called.
 func (c *Client) SiteFileSystem(kc keepClient) FileSystem {
+	root := &vdirnode{}
 	fs := &siteFileSystem{
 		fileSystem: fileSystem{
 			fsBackend: keepBackend{apiClient: c, keepClient: kc},
+			root:      root,
 		},
 	}
-	root := &treenode{
-		fs: fs,
+	root.inode = &treenode{
+		fs:     fs,
+		parent: root,
 		fileinfo: fileinfo{
 			name:    "/",
 			mode:    os.ModeDir | 0755,
@@ -34,13 +37,12 @@ func (c *Client) SiteFileSystem(kc keepClient) FileSystem {
 		},
 		inodes: make(map[string]inode),
 	}
-	root.parent = root
-	root.Child("by_id", func(inode) inode {
+	root.inode.Child("by_id", func(inode) inode {
 		var vn inode
 		vn = &vdirnode{
 			inode: &treenode{
 				fs:     fs,
-				parent: root,
+				parent: fs.root,
 				inodes: make(map[string]inode),
 				fileinfo: fileinfo{
 					name:    "by_id",
@@ -52,7 +54,6 @@ func (c *Client) SiteFileSystem(kc keepClient) FileSystem {
 		}
 		return vn
 	})
-	fs.root = root
 	return fs
 }
 
diff --git a/sdk/go/arvados/fs_site_test.go b/sdk/go/arvados/fs_site_test.go
index a8c369f..26a2212 100644
--- a/sdk/go/arvados/fs_site_test.go
+++ b/sdk/go/arvados/fs_site_test.go
@@ -6,6 +6,7 @@ package arvados
 
 import (
 	"net/http"
+	"os"
 
 	"git.curoverse.com/arvados.git/sdk/go/arvadostest"
 	check "gopkg.in/check.v1"
@@ -47,6 +48,12 @@ func (s *SiteFSSuite) TestByUUID(c *check.C) {
 	c.Check(err, check.IsNil)
 	c.Check(len(fis), check.Equals, 0)
 
+	err = s.fs.Mkdir("/by_id/"+arvadostest.FooCollection, 0755)
+	c.Check(err, check.Equals, os.ErrExist)
+
+	f, err = s.fs.Open("/by_id/" + arvadostest.NonexistentCollection)
+	c.Assert(err, check.Equals, os.ErrNotExist)
+
 	f, err = s.fs.Open("/by_id/" + arvadostest.FooCollection)
 	c.Assert(err, check.IsNil)
 	fis, err = f.Readdir(-1)
@@ -55,4 +62,18 @@ func (s *SiteFSSuite) TestByUUID(c *check.C) {
 		names = append(names, fi.Name())
 	}
 	c.Check(names, check.DeepEquals, []string{"foo"})
+
+	_, err = s.fs.OpenFile("/by_id/"+arvadostest.NonexistentCollection, os.O_RDWR|os.O_CREATE, 0755)
+	c.Check(err, check.Equals, ErrInvalidOperation)
+	err = s.fs.Rename("/by_id/"+arvadostest.FooCollection, "/by_id/beep")
+	c.Check(err, check.Equals, ErrInvalidArgument)
+	err = s.fs.Rename("/by_id/"+arvadostest.FooCollection+"/foo", "/by_id/beep")
+	c.Check(err, check.Equals, ErrInvalidArgument)
+	_, err = s.fs.Stat("/by_id/beep")
+	c.Check(err, check.Equals, os.ErrNotExist)
+	err = s.fs.Rename("/by_id/"+arvadostest.FooCollection+"/foo", "/by_id/"+arvadostest.FooCollection+"/bar")
+	c.Check(err, check.IsNil)
+
+	err = s.fs.Rename("/by_id", "/beep")
+	c.Check(err, check.Equals, ErrInvalidArgument)
 }

commit e585fcd60cdc0bf9f846e22241af7043364c9e47
Author: Tom Clegg <tclegg at veritasgenetics.com>
Date:   Sat Jan 13 13:39:19 2018 -0500

    12308: Add cgofuse to vendor file.
    
    Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tclegg at veritasgenetics.com>

diff --git a/vendor/vendor.json b/vendor/vendor.json
index aeac93e..1bff878 100644
--- a/vendor/vendor.json
+++ b/vendor/vendor.json
@@ -48,6 +48,12 @@
 			"revisionTime": "2016-12-14T20:08:43Z"
 		},
 		{
+			"checksumSHA1": "gMBls0ytB5wHvZizUQE8Eivv9WQ=",
+			"path": "github.com/curoverse/cgofuse/fuse",
+			"revision": "d08d9e36b4ca1364eb7a4eb9db0b7fa76c9250a2",
+			"revisionTime": "2017-12-17T05:18:50Z"
+		},
+		{
 			"checksumSHA1": "Gj+xR1VgFKKmFXYOJMnAczC3Znk=",
 			"path": "github.com/docker/distribution/digestset",
 			"revision": "277ed486c948042cab91ad367c379524f3b25e18",

commit c549ff8ad5a98d5f12f5081881fcb4e1ae392c1c
Merge: 8467390 707e31d
Author: Tom Clegg <tclegg at veritasgenetics.com>
Date:   Sat Jan 13 13:37:48 2018 -0500

    12308: Merge branch 'master' into 12308-go-fuse
    
    Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tclegg at veritasgenetics.com>


commit 8467390d785c59b4ab219e901ba3df63baf788e8
Merge: cda0f32 cd9b660
Author: Tom Clegg <tclegg at veritasgenetics.com>
Date:   Sun Jan 7 19:58:07 2018 -0500

    12308: Merge branch 'master' into 12308-go-fuse
    
    Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tclegg at veritasgenetics.com>

diff --cc build/run-build-packages-one-target.sh
index 2af01e3,983c221..c981b2a
--- a/build/run-build-packages-one-target.sh
+++ b/build/run-build-packages-one-target.sh
@@@ -161,7 -161,7 +161,8 @@@ pop
  
  if test -z "$packages" ; then
      packages="arvados-api-server
 +        arvados-client
+         arvados-docker-cleaner
          arvados-git-httpd
          arvados-node-manager
          arvados-src
diff --cc build/run-tests.sh
index ea2cbb0,f6c6e8f..b7fa273
--- a/build/run-tests.sh
+++ b/build/run-tests.sh
@@@ -479,14 -474,8 +479,14 @@@ export PERLLIB="$PERLINSTALLBASE/lib/pe
  
  export GOPATH
  mkdir -p "$GOPATH/src/git.curoverse.com"
 -rmdir --parents "$GOPATH/src/git.curoverse.com/arvados.git/tmp/GOPATH"
 -ln -snfT "$WORKSPACE" "$GOPATH/src/git.curoverse.com/arvados.git" \
 +rmdir -v --parents --ignore-fail-on-non-empty "$GOPATH/src/git.curoverse.com/arvados.git/tmp/GOPATH"
 +for d in \
 +    "$GOPATH/src/git.curoverse.com/arvados.git/arvados.git" \
 +    "$GOPATH/src/git.curoverse.com/arvados.git"; do
 +    [[ -d "$d" ]] && rmdir "$d"
 +    [[ -h "$d" ]] && rm "$d"
 +done
- ln -vsfT "$WORKSPACE" "$GOPATH/src/git.curoverse.com/arvados.git" \
++ln -vsnfT "$WORKSPACE" "$GOPATH/src/git.curoverse.com/arvados.git" \
      || fatal "symlink failed"
  go get -v github.com/kardianos/govendor \
      || fatal "govendor install failed"

commit cda0f329a1210b23fda9cd9fefc52ae925adb3cf
Author: Tom Clegg <tclegg at veritasgenetics.com>
Date:   Sun Jan 7 19:49:46 2018 -0500

    12308: Add mount subcommand tests.
    
    Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tclegg at veritasgenetics.com>

diff --git a/build/run-tests.sh b/build/run-tests.sh
index 46418be..ea2cbb0 100755
--- a/build/run-tests.sh
+++ b/build/run-tests.sh
@@ -74,6 +74,7 @@ doc
 lib/cli
 lib/cmd
 lib/crunchstat
+lib/mount
 services/api
 services/arv-git-httpd
 services/crunchstat
@@ -478,8 +479,14 @@ export PERLLIB="$PERLINSTALLBASE/lib/perl5:${PERLLIB:+$PERLLIB}"
 
 export GOPATH
 mkdir -p "$GOPATH/src/git.curoverse.com"
-rmdir --parents "$GOPATH/src/git.curoverse.com/arvados.git/tmp/GOPATH"
-ln -sfT "$WORKSPACE" "$GOPATH/src/git.curoverse.com/arvados.git" \
+rmdir -v --parents --ignore-fail-on-non-empty "$GOPATH/src/git.curoverse.com/arvados.git/tmp/GOPATH"
+for d in \
+    "$GOPATH/src/git.curoverse.com/arvados.git/arvados.git" \
+    "$GOPATH/src/git.curoverse.com/arvados.git"; do
+    [[ -d "$d" ]] && rmdir "$d"
+    [[ -h "$d" ]] && rm "$d"
+done
+ln -vsfT "$WORKSPACE" "$GOPATH/src/git.curoverse.com/arvados.git" \
     || fatal "symlink failed"
 go get -v github.com/kardianos/govendor \
     || fatal "govendor install failed"
@@ -837,6 +844,7 @@ gostuff=(
     lib/cli
     lib/cmd
     lib/crunchstat
+    lib/mount
     sdk/go/arvados
     sdk/go/arvadosclient
     sdk/go/blockdigest
diff --git a/lib/mount/command.go b/lib/mount/command.go
index b8e2791..88d268c 100644
--- a/lib/mount/command.go
+++ b/lib/mount/command.go
@@ -16,11 +16,24 @@ import (
 	"github.com/curoverse/cgofuse/fuse"
 )
 
-var Command = cmd{}
+var Command = &cmd{}
 
-type cmd struct{}
+type cmd struct {
+	// ready, if non-nil, will be closed when the mount is
+	// initialized.  If ready is non-nil, it RunCommand() should
+	// not be called more than once, or when ready is already
+	// closed.
+	ready chan struct{}
+	// It is safe to call Unmount ounly after ready has been
+	// closed.
+	Unmount func() (ok bool)
+}
 
-func (cmd) RunCommand(prog string, args []string, stdin io.Reader, stdout, stderr io.Writer) int {
+// RunCommand implements the subcommand "mount <path> [fuse options]".
+//
+// The "-d" fuse option (and perhaps other features) ignores the
+// stderr argument and prints to os.Stderr instead.
+func (c *cmd) RunCommand(prog string, args []string, stdin io.Reader, stdout, stderr io.Writer) int {
 	logger := log.New(stderr, prog+" ", 0)
 	flags := flag.NewFlagSet(args[0], flag.ContinueOnError)
 	ro := flags.Bool("ro", false, "read-only")
@@ -47,11 +60,12 @@ func (cmd) RunCommand(prog string, args []string, stdin io.Reader, stdout, stder
 		ReadOnly:   *ro,
 		Uid:        os.Getuid(),
 		Gid:        os.Getgid(),
+		ready:      c.ready,
 	})
-	notOK := host.Mount("", flags.Args())
-	if notOK {
+	c.Unmount = host.Unmount
+	ok := host.Mount("", flags.Args())
+	if !ok {
 		return 1
-	} else {
-		return 0
 	}
+	return 0
 }
diff --git a/lib/mount/command_test.go b/lib/mount/command_test.go
new file mode 100644
index 0000000..a8f6d1a
--- /dev/null
+++ b/lib/mount/command_test.go
@@ -0,0 +1,59 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+package mount
+
+import (
+	"bytes"
+	"io/ioutil"
+	"os"
+	"time"
+
+	check "gopkg.in/check.v1"
+)
+
+var _ = check.Suite(&CmdSuite{})
+
+type CmdSuite struct {
+	mnt string
+}
+
+func (s *CmdSuite) SetUpTest(c *check.C) {
+	tmpdir, err := ioutil.TempDir("", "")
+	c.Assert(err, check.IsNil)
+	s.mnt = tmpdir
+}
+
+func (s *CmdSuite) TearDownTest(c *check.C) {
+	c.Check(os.RemoveAll(s.mnt), check.IsNil)
+}
+
+func (s *CmdSuite) TestMount(c *check.C) {
+	exited := make(chan int)
+	stdin := bytes.NewBufferString("stdin")
+	stdout := bytes.NewBuffer(nil)
+	stderr := bytes.NewBuffer(nil)
+	mountCmd := cmd{ready: make(chan struct{})}
+	ready := false
+	go func() {
+		exited <- mountCmd.RunCommand("test mount", []string{s.mnt}, stdin, stdout, stderr)
+	}()
+	go func() {
+		<-mountCmd.ready
+		ready = true
+		ok := mountCmd.Unmount()
+		c.Check(ok, check.Equals, true)
+	}()
+	select {
+	case <-time.After(5 * time.Second):
+		c.Fatal("timed out")
+	case errCode, ok := <-exited:
+		c.Check(ok, check.Equals, true)
+		c.Check(errCode, check.Equals, 0)
+	}
+	c.Check(ready, check.Equals, true)
+	c.Check(stdout.String(), check.Equals, "")
+	// stdin should not have been read
+	c.Check(stdin.String(), check.Equals, "stdin")
+}
diff --git a/lib/mount/fs.go b/lib/mount/fs.go
index a6e2540..d269779 100644
--- a/lib/mount/fs.go
+++ b/lib/mount/fs.go
@@ -37,6 +37,10 @@ type keepFS struct {
 	open   map[uint64]*sharedFile
 	lastFH uint64
 	sync.Mutex
+
+	// If non-nil, this channel will be closed by Init() to notify
+	// other goroutines that the mount is ready.
+	ready chan struct{}
 }
 
 var (
@@ -66,6 +70,9 @@ func (fs *keepFS) lookupFH(fh uint64) *sharedFile {
 func (fs *keepFS) Init() {
 	defer fs.debugPanics()
 	fs.root = fs.Client.SiteFileSystem(fs.KeepClient)
+	if fs.ready != nil {
+		close(fs.ready)
+	}
 }
 
 func (fs *keepFS) Create(path string, flags int, mode uint32) (errc int, fh uint64) {
diff --git a/lib/mount/fs_test.go b/lib/mount/fs_test.go
index bcace0f..1e63b76 100644
--- a/lib/mount/fs_test.go
+++ b/lib/mount/fs_test.go
@@ -5,7 +5,45 @@
 package mount
 
 import (
+	"testing"
+
+	"git.curoverse.com/arvados.git/sdk/go/arvados"
+	"git.curoverse.com/arvados.git/sdk/go/arvadosclient"
+	"git.curoverse.com/arvados.git/sdk/go/keepclient"
 	"github.com/curoverse/cgofuse/fuse"
+	check "gopkg.in/check.v1"
 )
 
-var _ fuse.FileSystem = &keepFS{}
+// Gocheck boilerplate
+func Test(t *testing.T) {
+	check.TestingT(t)
+}
+
+var _ = check.Suite(&FSSuite{})
+
+type FSSuite struct{}
+
+func (*FSSuite) TestFuseInterface(c *check.C) {
+	var _ fuse.FileSystemInterface = &keepFS{}
+}
+
+func (*FSSuite) TestOpendir(c *check.C) {
+	client := arvados.NewClientFromEnv()
+	ac, err := arvadosclient.New(client)
+	c.Assert(err, check.IsNil)
+	kc, err := keepclient.MakeKeepClient(ac)
+	c.Assert(err, check.IsNil)
+
+	var fs fuse.FileSystemInterface = &keepFS{
+		Client:     client,
+		KeepClient: kc,
+	}
+	fs.Init()
+	errc, fh := fs.Opendir("/by_id")
+	c.Check(errc, check.Equals, 0)
+	c.Check(fh, check.Not(check.Equals), uint64(0))
+	c.Check(fh, check.Not(check.Equals), invalidFH)
+	errc, fh = fs.Opendir("/bogus")
+	c.Check(errc, check.Equals, -fuse.ENOENT)
+	c.Check(fh, check.Equals, invalidFH)
+}

-----------------------------------------------------------------------


hooks/post-receive
-- 




More information about the arvados-commits mailing list