1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: Apache-2.0
13 // pprof is only imported to register its HTTP handlers
17 "git.arvados.org/arvados.git/lib/cmd"
18 "git.arvados.org/arvados.git/sdk/go/arvados"
19 "git.arvados.org/arvados.git/sdk/go/arvadosclient"
20 "git.arvados.org/arvados.git/sdk/go/ctxlog"
21 "git.arvados.org/arvados.git/sdk/go/keepclient"
22 "github.com/arvados/cgofuse/fuse"
23 "github.com/ghodss/yaml"
24 "github.com/sirupsen/logrus"
27 var Command = &mountCommand{}
29 type mountCommand struct {
30 // ready, if non-nil, will be closed when the mount is
31 // initialized. If ready is non-nil, it RunCommand() should
32 // not be called more than once, or when ready is already
33 // closed. Only intended for testing.
35 // It is safe to call Unmount only after ready has been
37 Unmount func() (ok bool)
40 // RunCommand implements the subcommand "mount <path> [fuse options]".
42 // The "-d" fuse option (and perhaps other features) ignores the
43 // stderr argument and prints to os.Stderr instead.
44 func (c *mountCommand) RunCommand(prog string, args []string, stdin io.Reader, stdout, stderr io.Writer) int {
45 logger := ctxlog.New(stderr, "text", "info")
46 defer logger.Debug("exiting")
48 flags := flag.NewFlagSet(prog, flag.ContinueOnError)
49 ro := flags.Bool("ro", false, "read-only")
50 experimental := flags.Bool("experimental", false, "acknowledge this is an experimental command, and should not be used in production (required)")
51 cacheSizeStr := flags.String("cache-size", "0", "cache size as percent of home filesystem size (\"5%\") or size (\"10GiB\") or 0 for automatic")
52 logLevel := flags.String("log-level", "info", "logging level (debug, info, ...)")
53 debug := flags.Bool("debug", false, "alias for -log-level=debug")
54 pprof := flags.String("pprof", "", "serve Go profile data at `[addr]:port`")
55 if ok, code := cmd.ParseFlags(flags, prog, args, "[FUSE mount options]", stderr); !ok {
59 logger.Errorf("experimental command %q used without --experimental flag", prog)
62 lvl, err := logrus.ParseLevel(*logLevel)
64 logger.WithError(err).Error("invalid argument for -log-level flag")
68 lvl = logrus.DebugLevel
73 log.Println(http.ListenAndServe(*pprof, nil))
77 client := arvados.NewClientFromEnv()
78 if err := yaml.Unmarshal([]byte(*cacheSizeStr), &client.DiskCacheSize); err != nil {
79 logger.Errorf("error parsing -cache-size argument: %s", err)
82 ac, err := arvadosclient.New(client)
87 kc, err := keepclient.MakeKeepClient(ac)
92 host := fuse.NewFileSystemHost(&keepFS{
101 c.Unmount = host.Unmount
103 logger.WithField("mountargs", flags.Args()).Debug("mounting")
104 ok := host.Mount("", flags.Args())