Example #1
0
File: fs.go Project: ncw/rclone
// 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
}
Example #2
0
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
}
Example #3
0
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
}
Example #5
0
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)
	}
}
Example #6
0
// 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
}
Example #7
0
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
}
Example #8
0
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
}
Example #9
0
// 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
}
Example #10
0
File: mount.go Project: ovh/svfs
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
}
Example #11
0
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)
	}
}
Example #12
0
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
}
Example #13
0
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
}
Example #14
0
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
	}
}
Example #15
0
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)
	}
}
Example #16
0
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")
	}
}
Example #17
0
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
}
Example #18
0
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)
}