// mountOptions configures the options from the command line flags func mountOptions(device string) (options []fuse.MountOption) { options = []fuse.MountOption{ fuse.MaxReadahead(uint32(maxReadAhead)), fuse.Subtype("rclone"), fuse.FSName(device), fuse.VolumeName(device), fuse.NoAppleDouble(), fuse.NoAppleXattr(), // Options from benchmarking in the fuse module //fuse.MaxReadahead(64 * 1024 * 1024), //fuse.AsyncRead(), - FIXME this causes // ReadFileHandle.Read error: read /home/files/ISOs/xubuntu-15.10-desktop-amd64.iso: bad file descriptor // which is probably related to errors people are having //fuse.WritebackCache(), } if allowNonEmpty { options = append(options, fuse.AllowNonEmptyMount()) } if allowOther { options = append(options, fuse.AllowOther()) } if allowRoot { options = append(options, fuse.AllowRoot()) } if defaultPermissions { options = append(options, fuse.DefaultPermissions()) } if readOnly { options = append(options, fuse.ReadOnly()) } if writebackCache { options = append(options, fuse.WritebackCache()) } return options }
func (m *mounter) Mount( address string, mountPoint string, shard uint64, modulus uint64, ) (retErr error) { // TODO: should we make the caller do this? if err := os.MkdirAll(mountPoint, 0777); err != nil { return err } name := namePrefix + address conn, err := fuse.Mount( mountPoint, fuse.FSName(name), fuse.VolumeName(name), fuse.Subtype(subtype), fuse.AllowOther(), fuse.WritebackCache(), fuse.MaxReadahead(1<<32-1), ) if err != nil { return err } defer func() { if err := conn.Close(); err != nil && retErr == nil { retErr = err } }() if err := fs.Serve(conn, newFilesystem(m.apiClient, shard, modulus)); err != nil { return err } <-conn.Ready return conn.MountError }
func (m *mounter) Mount( mountPoint string, shard *pfsclient.Shard, commitMounts []*CommitMount, ready chan bool, debug bool, ) (retErr error) { var once sync.Once defer once.Do(func() { if ready != nil { close(ready) } }) name := namePrefix + m.address conn, err := fuse.Mount( mountPoint, fuse.FSName(name), fuse.VolumeName(name), fuse.Subtype(subtype), fuse.AllowOther(), fuse.WritebackCache(), fuse.MaxReadahead(1<<32-1), ) if err != nil { return err } defer func() { if err := conn.Close(); err != nil && retErr == nil { retErr = err } }() sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, os.Interrupt) go func() { <-sigChan m.Unmount(mountPoint) }() once.Do(func() { if ready != nil { close(ready) } }) config := &fs.Config{} if debug { config.Debug = func(msg interface{}) { lion.Printf("%+v", msg) } } if err := fs.New(conn, config).Serve(newFilesystem(m.apiClient, shard, commitMounts)); err != nil { return err } <-conn.Ready return conn.MountError }
// NewConnSrc returns a source of new connections based on Lookups in the // provided mount directory. If there isn't a directory located at tmpdir one // is created. The second return parameter can be used to shutdown and release // any resources. As a result of this shutdown, or during any other fatal // error, the returned chan will be closed. // // The connset parameter is optional. func NewConnSrc(mountdir, tmpdir string, connset *proxy.ConnSet) (<-chan proxy.Conn, io.Closer, error) { if err := os.MkdirAll(tmpdir, 0777); err != nil { return nil, nil, err } if err := fuse.Unmount(mountdir); err != nil { // The error is too verbose to be useful to print out } log.Printf("Mounting %v...", mountdir) c, err := fuse.Mount(mountdir, fuse.AllowOther()) if err != nil { return nil, nil, fmt.Errorf("cannot mount %q: %v", mountdir, err) } log.Printf("Mounted %v", mountdir) if connset == nil { // Make a dummy one. connset = proxy.NewConnSet() } conns := make(chan proxy.Conn, 1) root := &fsRoot{ tmpDir: tmpdir, linkDir: mountdir, dst: conns, links: make(map[string]symlink), closers: []io.Closer{c}, connset: connset, } server := fs.New(c, &fs.Config{ Debug: func(msg interface{}) { if false { log.Print(msg) } }, }) go func() { if err := server.Serve(root); err != nil { log.Printf("serve %q exited due to error: %v", mountdir, err) } // The server exited but we don't know whether this is because of a // graceful reason (via root.Close) or via an external force unmounting. // Closing the root will ensure the 'dst' chan is closed correctly to // signify that no new connections are possible. if err := root.Close(); err != nil { log.Printf("root.Close() error: %v", err) } log.Printf("FUSE exited") }() return conns, root, nil }
func TestMountOptionAllowRootThenAllowOther(t *testing.T) { t.Parallel() mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}}, fuse.AllowRoot(), fuse.AllowOther(), ) if err == nil { mnt.Close() } if g, e := err, fuse.ErrCannotCombineAllowOtherAndAllowRoot; g != e { t.Fatalf("wrong error: %v != %v", g, e) } }
// Mounts the filesystem func (this *FileSystem) Mount() (*fuse.Conn, error) { conn, err := fuse.Mount( this.MountPoint, fuse.FSName("hdfs"), fuse.Subtype("hdfs"), fuse.VolumeName("HDFS filesystem"), fuse.AllowOther(), fuse.WritebackCache(), fuse.MaxReadahead(1024*64)) //TODO: make configurable if err != nil { return nil, err } this.Mounted = true return conn, nil }
func (m *mounter) Mount( repositoryName string, commitID string, mountPoint string, shard uint64, modulus uint64, ) (retErr error) { // TODO(pedge): should we make the caller do this? if err := os.MkdirAll(mountPoint, 0777); err != nil { return err } name := namePrefix + repositoryName if commitID != "" { name = name + "-" + commitID } conn, err := fuse.Mount( mountPoint, fuse.FSName(name), fuse.VolumeName(name), fuse.Subtype(subtype), fuse.AllowOther(), fuse.WritebackCache(), fuse.MaxReadahead(1<<32-1), ) if err != nil { return err } errChan := make(chan error, 1) m.lock.Lock() if _, ok := m.mountpointToErrChan[mountPoint]; ok { m.lock.Unlock() return fmt.Errorf("mountpoint %s already exists", mountPoint) } m.mountpointToErrChan[mountPoint] = errChan m.lock.Unlock() go func() { err := fs.Serve(conn, newFilesystem(m.apiClient, repositoryName, commitID, shard, modulus)) closeErr := conn.Close() if err != nil { errChan <- err } else { errChan <- closeErr } }() <-conn.Ready return conn.MountError }
func (m *mounter) Mount( mountPoint string, shard *pfs.Shard, commitMounts []*CommitMount, ready chan bool, ) (retErr error) { var once sync.Once defer once.Do(func() { if ready != nil { close(ready) } }) // TODO: should we make the caller do this? if err := os.MkdirAll(mountPoint, 0777); err != nil { return err } name := namePrefix + m.address conn, err := fuse.Mount( mountPoint, fuse.FSName(name), fuse.VolumeName(name), fuse.Subtype(subtype), fuse.AllowOther(), fuse.WritebackCache(), fuse.MaxReadahead(1<<32-1), ) if err != nil { return err } defer func() { if err := conn.Close(); err != nil && retErr == nil { retErr = err } }() once.Do(func() { if ready != nil { close(ready) } }) if err := fs.Serve(conn, newFilesystem(m.apiClient, shard, commitMounts)); err != nil { return err } <-conn.Ready return conn.MountError }
// mount calls the fuse library to specify // the details of the mounted filesystem. func mount(path, mountpoint string) error { // TODO: Check that there is no folder named mountOptions := []fuse.MountOption{ fuse.FSName("MuLi"), fuse.Subtype("MuLiFS"), fuse.LocalVolume(), fuse.VolumeName("Music Library"), } if config_params.allow_users { mountOptions = append(mountOptions, fuse.AllowOther()) } else { if config_params.allow_root { mountOptions = append(mountOptions, fuse.AllowRoot()) } } // playlist or drop in the path. c, err := fuse.Mount( mountpoint, mountOptions...) if err != nil { return err } defer c.Close() filesys := &FS{ mPoint: path, } if err := fs.Serve(c, filesys); err != nil { return err } // check if the mount process has an error to report <-c.Ready if err := c.MountError; err != nil { return err } return nil }
func mountOptions(device string) (options []fuse.MountOption) { if svfs.AllowOther { options = append(options, fuse.AllowOther()) } if svfs.AllowRoot { options = append(options, fuse.AllowRoot()) } if svfs.DefaultPermissions { options = append(options, fuse.DefaultPermissions()) } if svfs.ReadOnly { options = append(options, fuse.ReadOnly()) } options = append(options, fuse.MaxReadahead(uint32(svfs.ReadAheadSize))) options = append(options, fuse.Subtype("svfs")) options = append(options, fuse.FSName(device)) return options }
func main() { flag.Usage = usage flag.Parse() if *mount == "" || *mirror == "" { usage() os.Exit(2) } c, err := fuse.Mount( *mount, fuse.FSName("mirrorfs"), fuse.Subtype("mirrorfs"), fuse.VolumeName("Mirror FS"), // fuse.LocalVolume(), fuse.AllowOther(), ) if err != nil { log.Fatal(err) } defer c.Close() cfg := &fs.Config{} if *debug { cfg.Debug = debugLog } srv := fs.New(c, cfg) filesys := mirrorfs.NewMirrorFS(*mirror) if err := srv.Serve(filesys); err != nil { log.Fatal(err) } // Check if the mount process has an error to report. <-c.Ready if err := c.MountError; err != nil { log.Fatal(err) } }
func Serve(mountPoint, cgroupDir string) error { c, err := fuse.Mount( mountPoint, fuse.FSName("cgroupfs"), fuse.Subtype("cgroupfs"), fuse.LocalVolume(), fuse.VolumeName("cgroup volume"), fuse.AllowOther(), ) if err != nil { return err } defer c.Close() go handleStopSignals(mountPoint) var srv *fusefs.Server if os.Getenv("FUSE_DEBUG") != "" { srv = fusefs.New(c, &fusefs.Config{ Debug: func(msg interface{}) { fmt.Printf("%s\n", msg) }, }) } else { srv = fusefs.New(c, nil) } err = srv.Serve(fs.FS{cgroupDir}) if err != nil { return err } // check if the mount process has an error to report <-c.Ready if err := c.MountError; err != nil { return err } return nil }
func process(c *Config) (conn *fuse.Conn, err error) { if err = fuse.Unmount(c.Base); err == nil { logex.Info("last not unmount") time.Sleep(1000 * time.Millisecond) err = nil } else { err = nil } ops := []fuse.MountOption{ fuse.AllowOther(), fuse.FSName(FsName), fuse.LocalVolume(), } conn, err = fuse.Mount(c.Base, ops...) if err != nil { return nil, logex.Trace(err) } go fs.Serve(conn, NewTree("/", c.Target)) logex.Info("connected.") return conn, nil }
func run() error { flag.Usage = usage flag.Parse() if *debug { fuse.Debug = func(v interface{}) { log.Println("[fuse]", v) } } var subdir, mountpoint string switch flag.NArg() { case 1: subdir = "/" mountpoint = flag.Arg(0) case 2: subdir = path.Join("/", flag.Arg(0)) mountpoint = flag.Arg(1) default: usage() os.Exit(1) } var endpoints []string if ep := os.Getenv("ETCD_ENDPOINTS"); ep != "" { endpoints = strings.Split(ep, ",") } else { endpoints = []string{"localhost:4001"} } log.Printf("Using endpoints %v", endpoints) cfg := client.Config{ Endpoints: endpoints, } etcd, err := client.New(cfg) if err != nil { return err } var mountOpts []fuse.MountOption if *allowOther { mountOpts = append(mountOpts, fuse.AllowOther()) } if *allowRoot { mountOpts = append(mountOpts, fuse.AllowRoot()) } mountOpts = append(mountOpts, fuse.DefaultPermissions()) mountOpts = append(mountOpts, fuse.FSName("etcd:"+subdir)) mountOpts = append(mountOpts, fuse.ReadOnly()) mountOpts = append(mountOpts, fuse.Subtype("etcdFS")) log.Printf("Mounting etcd:%s to %s", subdir, mountpoint) c, err := fuse.Mount( mountpoint, mountOpts..., ) if err != nil { return err } defer c.Close() srv := fs.New(c, nil) filesys := &etcdFS{ etcd: client.NewKeysAPI(etcd), base: subdir, } errch := make(chan error) log.Printf("Start serving") go func() { errch <- srv.Serve(filesys) }() <-c.Ready if c.MountError != nil { return c.MountError } sigs := make(chan os.Signal) signal.Notify(sigs, syscall.SIGHUP, syscall.SIGINT, syscall.SIGKILL, syscall.SIGTERM) select { case err := <-errch: return err case s := <-sigs: log.Printf("Caught signal: %v", s) err := c.Close() log.Printf("Error: %v", err) return err } }
func main() { runtime.GOMAXPROCS(runtime.NumCPU()) runtime.SetBlockProfileRate(1) flag.Usage = Usage flag.Parse() if flag.NArg() != 1 { Usage() os.Exit(2) } mountpoint := flag.Arg(0) if *debugGdrive { debug = true } userCurrent, err := user.Current() if err != nil { log.Fatalf("unable to get UID/GID of current user: %v", err) } uidInt, err := strconv.Atoi(userCurrent.Uid) if err != nil { log.Fatalf("unable to get UID/GID of current user: %v", err) } uid := uint32(uidInt) gidInt, err := strconv.Atoi(userCurrent.Gid) if err != nil { log.Fatalf("unable to get UID/GID of current user: %v", err) } gid := uint32(gidInt) if err = sanityCheck(mountpoint); err != nil { log.Fatalf("sanityCheck failed: %s\n", err) } http.HandleFunc("/", RootHandler) go http.ListenAndServe(fmt.Sprintf("localhost:%s", *port), nil) var client *http.Client if *readOnly { client = getOAuthClient(drive.DriveReadonlyScope) } else { client = getOAuthClient(drive.DriveScope) } driveCache := cache.NewCache("/tmp", client) // TODO: move into drivedb, so we don't create a service twice service, _ := drive.New(client) about, err := service.About.Get().Do() if err != nil { log.Fatalf("drive.service.About.Get().Do: %v\n", err) } // fileId of the root of the FS (aka "My Drive") rootId := about.RootFolderId // email address of the mounted google drive account account := about.User.EmailAddress // Ensure the token's always fresh // TODO: Remove this once goauth2 changes are accepted upstream // https://code.google.com/p/goauth2/issues/detail?id=47 go tokenKicker(client, 59*time.Minute) // Create and start the drive metadata syncer. db, err := drive_db.NewDriveDB(client, *dbDir, *cacheDir, *driveMetadataLatency, rootId) if err != nil { log.Fatalf("could not open leveldb: %v", err) } defer db.Close() db.WaitUntilSynced() log.Printf("synced!") options := []fuse.MountOption{ fuse.FSName("GoogleDrive"), fuse.Subtype("gdrive"), fuse.VolumeName(account), } if *allowOther { options = append(options, fuse.AllowOther()) } if *readOnly { options = append(options, fuse.ReadOnly()) } c, err := fuse.Mount(mountpoint, options...) if err != nil { log.Fatal(err) } defer c.Close() // Trap control-c (sig INT) and unmount sig := make(chan os.Signal, 1) signal.Notify(sig, os.Interrupt) go func() { for _ = range sig { if err := fuse.Unmount(mountpoint); err != nil { log.Printf("fuse.Unmount failed: %v", err) } } }() sc := serveConn{db: db, driveCache: driveCache, service: service, uid: uid, gid: gid, writers: make(map[int]io.PipeWriter), conn: c, } err = sc.Serve() if err != nil { log.Fatalln("fuse server failed: ", err) } // check if the mount process has an error to report <-c.Ready if err := c.MountError; err != nil { log.Fatal(err) } }
func main() { allowOther := flag.Bool("allow-other", false, "allow all users access to the filesystem") allowRoot := flag.Bool("allow-root", false, "allow root to access the filesystem") debug := flag.Bool("debug", false, "enable debug output") gid := flag.Int("gid", os.Getgid(), "set the GID that should own all files") perm := flag.Int("perm", 0, "set the file permission flags for all files") ro := flag.Bool("ro", false, "mount the filesystem read-only") root := flag.String("root", "", "path in Consul to the root of the filesystem") timeout := flag.String("timeout", defaultTimeout, "timeout for Consul requests") uid := flag.Int("uid", os.Getuid(), "set the UID that should own all files") flag.Parse() logger := logrus.New() if *debug { logger.Level = logrus.DebugLevel } consulConfig := &consul.Config{} var mountPoint string switch flag.NArg() { case 1: mountPoint = flag.Arg(0) case 2: consulConfig.Address = flag.Arg(0) mountPoint = flag.Arg(1) default: flag.Usage() } // Initialize a Consul client. TODO: connection parameters client, err := consul.NewClient(consulConfig) if err != nil { logrus.NewEntry(logger).WithError(err).Error("could not initialize consul") os.Exit(1) } // Configure some mount options timeoutDuration, err := time.ParseDuration(*timeout) if err != nil { logrus.NewEntry(logger).WithError(err).Fatal("invalid -timeout value") } mountOptions := []fuse.MountOption{ fuse.DefaultPermissions(), fuse.DaemonTimeout(fmt.Sprint(int64(timeoutDuration.Seconds() + 1))), fuse.NoAppleDouble(), fuse.NoAppleXattr(), } if *allowOther { mountOptions = append(mountOptions, fuse.AllowOther()) } if *allowRoot { mountOptions = append(mountOptions, fuse.AllowRoot()) } if *ro { mountOptions = append(mountOptions, fuse.ReadOnly()) } // Mount the file system to start receiving FS events at the mount point. logger.WithField("location", mountPoint).Info("mounting kvfs") conn, err := fuse.Mount(mountPoint, mountOptions...) if err != nil { logrus.NewEntry(logger).WithError(err).Fatal("error mounting kvfs") } defer conn.Close() // Try to cleanly unmount the FS if SIGINT or SIGTERM is received sigs := make(chan os.Signal, 10) signal.Notify(sigs, os.Interrupt, syscall.SIGTERM) go func() { for sig := range sigs { logger.WithField("signal", sig).Info("attempting to unmount") err := fuse.Unmount(mountPoint) if err != nil { logrus.NewEntry(logger).WithError(err).Error("cannot unmount") } } }() // Create a file system object and start handing its requests server := fs.New(conn, &fs.Config{ Debug: func(m interface{}) { logger.Debug(m) }, WithContext: func(ctx context.Context, req fuse.Request) context.Context { // The returned cancel function doesn't matter: the request handler will // cancel the parent context at the end of the request. newCtx, _ := context.WithTimeout(ctx, timeoutDuration) return newCtx }, }) f := &consulfs.ConsulFS{ Consul: &consulfs.CancelConsulKV{ Client: client, Logger: logger, }, Logger: logger, UID: uint32(*uid), GID: uint32(*gid), Perms: os.FileMode(*perm), RootPath: *root, } err = server.Serve(f) if err != nil { // Not sure what would cause Serve() to exit with an error logrus.NewEntry(logger).WithError(err).Error("error serving filesystem") } // Wait for the FUSE connection to end <-conn.Ready if conn.MountError != nil { logrus.NewEntry(logger).WithError(conn.MountError).Error("unmount error") os.Exit(1) } else { logger.Info("file system exiting normally") } }
func (this *Mount) Run(args []string) (exitCode int) { cmdFlags := flag.NewFlagSet("mount", flag.ContinueOnError) cmdFlags.Usage = func() { this.Ui.Output(this.Help()) } cmdFlags.StringVar(&this.zone, "z", ctx.ZkDefaultZone(), "") cmdFlags.StringVar(&this.cluster, "c", "", "") cmdFlags.StringVar(&this.logLevel, "l", "info", "") if err := cmdFlags.Parse(args); err != nil { return 1 } if validateArgs(this, this.Ui). on("-z", "-c"). invalid(args) { return 2 } this.mountPoint = args[len(args)-1] if !strings.HasPrefix(this.mountPoint, "/") { this.Ui.Error("mount point must start with /") return 1 } setupLogging("stdout", this.logLevel, "") c, err := fuse.Mount( this.mountPoint, fuse.FSName("kfs"), fuse.Subtype("kfs"), fuse.VolumeName("Kafka FS"), fuse.ReadOnly(), fuse.AllowOther(), ) if err != nil { log.Critical(err) } signal.RegisterHandler(func(sig os.Signal) { var err error for i := 0; i < 5; i++ { err = fuse.Unmount(this.mountPoint) if err == nil { break } log.Warn(err) time.Sleep(time.Second * 5) } if err == nil { log.Info("Kafka FS unmounted") } else { log.Error("Kafka FS unable to umount") } c.Close() os.Exit(0) }, syscall.SIGINT, syscall.SIGTERM) srv := fs.New(c, &fs.Config{}) fs := kfs.New(this.zone, this.cluster) if err := srv.Serve(fs); err != nil { log.Error(err) } <-c.Ready if err := c.MountError; err != nil { log.Error(err) } return }
func main() { // Process command line arguments var token string var acctNum string var fsNum string var serverAddr string app := cli.NewApp() app.Name = "cfs" app.Usage = "Client used to test filesysd" app.Version = "0.5.0" app.Flags = []cli.Flag{ cli.StringFlag{ Name: "token, T", Value: "", Usage: "Access token", EnvVar: "OOHHC_TOKEN_KEY", Destination: &token, }, } app.Commands = []cli.Command{ { Name: "show", Usage: "Show a File Systems", ArgsUsage: "<region>://<account uuid>/<file system uuid>", Action: func(c *cli.Context) { if !c.Args().Present() { fmt.Println("Invalid syntax for show.") os.Exit(1) } if token == "" { fmt.Println("Token is required") os.Exit(1) } serverAddr, acctNum, fsNum = parseurl(c.Args().Get(0), "8448") if fsNum == "" { fmt.Println("Missing file system id") os.Exit(1) } conn := setupWS(serverAddr) ws := mb.NewFileSystemAPIClient(conn) result, err := ws.ShowFS(context.Background(), &mb.ShowFSRequest{Acctnum: acctNum, FSid: fsNum, Token: token}) if err != nil { log.Fatalf("Bad Request: %v", err) conn.Close() os.Exit(1) } conn.Close() log.Printf("Result: %s\n", result.Status) log.Printf("SHOW Results: %s", result.Payload) }, }, { Name: "create", Usage: "Create a File Systems", ArgsUsage: "<region>://<account uuid> -N <file system name>", Flags: []cli.Flag{ cli.StringFlag{ Name: "name, N", Value: "", Usage: "Name of the file system", }, }, Action: func(c *cli.Context) { if !c.Args().Present() { fmt.Println("Invalid syntax for show.") os.Exit(1) } if token == "" { fmt.Println("Token is required") } // For create serverAddr and acctnum are required serverAddr, acctNum, _ = parseurl(c.Args().Get(0), "8448") if c.String("name") == "" { fmt.Println("File system name is a required field.") os.Exit(1) } conn := setupWS(serverAddr) ws := mb.NewFileSystemAPIClient(conn) result, err := ws.CreateFS(context.Background(), &mb.CreateFSRequest{Acctnum: acctNum, FSName: c.String("name"), Token: token}) if err != nil { log.Fatalf("Bad Request: %v", err) conn.Close() os.Exit(1) } conn.Close() log.Printf("Result: %s\n", result.Status) log.Printf("Create Results: %s", result.Payload) }, }, { Name: "list", Usage: "List File Systems for an account", ArgsUsage: "<region>://<account uuid>", Action: func(c *cli.Context) { if !c.Args().Present() { fmt.Println("Invalid syntax for list.") os.Exit(1) } if token == "" { fmt.Println("Token is required") os.Exit(1) } serverAddr, acctNum, _ = parseurl(c.Args().Get(0), "8448") conn := setupWS(serverAddr) ws := mb.NewFileSystemAPIClient(conn) result, err := ws.ListFS(context.Background(), &mb.ListFSRequest{Acctnum: acctNum, Token: token}) if err != nil { log.Fatalf("Bad Request: %v", err) conn.Close() os.Exit(1) } conn.Close() log.Printf("Result: %s\n", result.Status) log.Printf("LIST Results: %s", result.Payload) }, }, { Name: "delete", Usage: "Delete a File Systems", ArgsUsage: "<region>://<account uuid>/<file system uuid>", Action: func(c *cli.Context) { if !c.Args().Present() { fmt.Println("Invalid syntax for delete.") os.Exit(1) } if token == "" { fmt.Println("Token is required") } serverAddr, acctNum, fsNum = parseurl(c.Args().Get(0), "8448") if fsNum == "" { fmt.Println("Missing file system id") os.Exit(1) } conn := setupWS(serverAddr) ws := mb.NewFileSystemAPIClient(conn) result, err := ws.DeleteFS(context.Background(), &mb.DeleteFSRequest{Acctnum: acctNum, FSid: fsNum, Token: token}) if err != nil { log.Fatalf("Bad Request: %v", err) conn.Close() os.Exit(1) } conn.Close() log.Printf("Result: %s\n", result.Status) log.Printf("Delete Results: %s", result.Payload) }, }, { Name: "update", Usage: "Update a File Systems", ArgsUsage: "<region>://<account uuid>/<file system uuid> -o [OPTIONS]", Flags: []cli.Flag{ cli.StringFlag{ Name: "name, N", Value: "", Usage: "Name of the file system", }, cli.StringFlag{ Name: "S, status", Value: "", Usage: "Status of the file system", }, }, Action: func(c *cli.Context) { if !c.Args().Present() { fmt.Println("Invalid syntax for update.") os.Exit(1) } if token == "" { fmt.Println("Token is required") os.Exit(1) } serverAddr, acctNum, fsNum = parseurl(c.Args().Get(0), "8448") if fsNum == "" { fmt.Println("Missing file system id") os.Exit(1) } if c.String("name") != "" { fmt.Printf("Invalid File System String: %q\n", c.String("name")) os.Exit(1) } fsMod := &mb.ModFS{ Name: c.String("name"), Status: c.String("status"), } conn := setupWS(serverAddr) ws := mb.NewFileSystemAPIClient(conn) result, err := ws.UpdateFS(context.Background(), &mb.UpdateFSRequest{Acctnum: acctNum, FSid: fsNum, Token: token, Filesys: fsMod}) if err != nil { log.Fatalf("Bad Request: %v", err) conn.Close() os.Exit(1) } conn.Close() log.Printf("Result: %s\n", result.Status) log.Printf("Update Results: %s", result.Payload) }, }, { Name: "grant", Usage: "Grant an Addr access to a File Systems", ArgsUsage: "<region>://<account uuid>/<file system uuid> -addr <IP Address>", Flags: []cli.Flag{ cli.StringFlag{ Name: "addr", Value: "", Usage: "Address to Grant", }, }, Action: func(c *cli.Context) { if !c.Args().Present() { fmt.Println("Invalid syntax for delete.") os.Exit(1) } if token == "" { fmt.Println("Token is required") os.Exit(1) } if c.String("addr") == "" { fmt.Println("addr is required") os.Exit(1) } serverAddr, acctNum, fsNum = parseurl(c.Args().Get(0), "8448") if fsNum == "" { fmt.Println("Missing file system id") os.Exit(1) } conn := setupWS(serverAddr) ws := mb.NewFileSystemAPIClient(conn) result, err := ws.GrantAddrFS(context.Background(), &mb.GrantAddrFSRequest{Acctnum: acctNum, FSid: fsNum, Token: token, Addr: c.String("addr")}) if err != nil { log.Fatalf("Bad Request: %v", err) conn.Close() os.Exit(1) } conn.Close() log.Printf("Result: %s\n", result.Status) }, }, { Name: "revoke", Usage: "Revoke an Addr's access to a File Systems", ArgsUsage: "<region>://<account uuid>/<file system uuid> -addr <IP Address>", Flags: []cli.Flag{ cli.StringFlag{ Name: "addr", Value: "", Usage: "Address to Revoke", }, }, Action: func(c *cli.Context) { if !c.Args().Present() { fmt.Println("Invalid syntax for revoke.") os.Exit(1) } if token == "" { fmt.Println("Token is required") os.Exit(1) } if c.String("addr") == "" { fmt.Println("addr is required") os.Exit(1) } serverAddr, acctNum, fsNum = parseurl(c.Args().Get(0), "8448") if fsNum == "" { fmt.Println("Missing file system id") os.Exit(1) } conn := setupWS(serverAddr) ws := mb.NewFileSystemAPIClient(conn) result, err := ws.RevokeAddrFS(context.Background(), &mb.RevokeAddrFSRequest{Acctnum: acctNum, FSid: fsNum, Token: token, Addr: c.String("addr")}) if err != nil { log.Fatalf("Bad Request: %v", err) conn.Close() os.Exit(1) } conn.Close() log.Printf("Result: %s\n", result.Status) }, }, { Name: "verify", Usage: "Verify an Addr has access to a file system", ArgsUsage: "<region>://<account uuid>/<file system uuid> -addr <IP Address>", Flags: []cli.Flag{ cli.StringFlag{ Name: "addr", Value: "", Usage: "Address to check", }, }, Action: func(c *cli.Context) { if !c.Args().Present() { fmt.Println("Invalid syntax for revoke.") os.Exit(1) } if c.String("addr") == "" { fmt.Println("addr is required") os.Exit(1) } serverAddr, fsNum, _ = parseurl(c.Args().Get(0), "8448") conn := setupWS(serverAddr) ws := mb.NewFileSystemAPIClient(conn) result, err := ws.LookupAddrFS(context.Background(), &mb.LookupAddrFSRequest{FSid: fsNum, Addr: c.String("addr")}) if err != nil { log.Fatalf("Bad Request: %v", err) conn.Close() os.Exit(1) } conn.Close() log.Printf("Result: %s\n", result.Status) }, }, { Name: "mount", Usage: "mount a file system", ArgsUsage: "<region>://<file system uuid> <mount point> -o [OPTIONS]", Flags: []cli.Flag{ cli.StringFlag{ Name: "o", Value: "", Usage: "mount options", }, }, Action: func(c *cli.Context) { if !c.Args().Present() { fmt.Println("Invalid syntax for revoke.") os.Exit(1) } serverAddr, fsNum, _ = parseurl(c.Args().Get(0), "8445") fsnum, err := uuid.FromString(fsNum) if err != nil { fmt.Print("File System id is not valid: ", err) } mountpoint := c.Args().Get(1) // check mountpoint exists if _, ferr := os.Stat(mountpoint); os.IsNotExist(ferr) { log.Printf("Mount point %s does not exist\n\n", mountpoint) os.Exit(1) } fusermountPath() // process file system options if c.String("o") != "" { clargs := getArgs(c.String("o")) // crapy debug log handling :) if debug, ok := clargs["debug"]; ok { if debug == "false" { log.SetFlags(0) log.SetOutput(ioutil.Discard) } } else { log.SetFlags(0) log.SetOutput(ioutil.Discard) } } // Setup grpc var opts []grpc.DialOption creds := credentials.NewTLS(&tls.Config{ InsecureSkipVerify: true, }) opts = append(opts, grpc.WithTransportCredentials(creds)) conn, err := grpc.Dial(serverAddr, opts...) if err != nil { log.Fatalf("failed to dial: %v", err) } defer conn.Close() // Work with fuse cfs, err := fuse.Mount( mountpoint, fuse.FSName("cfs"), fuse.Subtype("cfs"), fuse.LocalVolume(), fuse.VolumeName("CFS"), fuse.AllowOther(), fuse.DefaultPermissions(), ) if err != nil { log.Fatal(err) } defer cfs.Close() rpc := newrpc(conn) fs := newfs(cfs, rpc, fsnum.String()) err = fs.InitFs() if err != nil { log.Fatal(err) } srv := newserver(fs) if err := srv.serve(); err != nil { log.Fatal(err) } <-cfs.Ready if err := cfs.MountError; err != nil { log.Fatal(err) } }, }, } app.Run(os.Args) }