github.com/sagansystems/goofys-app@v0.19.1-0.20180410053237-b2302fdf5af9/api/api.go (about)

     1  package goofys
     2  
     3  import (
     4  	. "github.com/kahing/goofys/internal"
     5  
     6  	"context"
     7  	"fmt"
     8  	"net"
     9  	"net/http"
    10  	"os"
    11  	"os/exec"
    12  	"time"
    13  
    14  	"github.com/aws/aws-sdk-go/aws"
    15  	"github.com/aws/aws-sdk-go/aws/credentials"
    16  
    17  	"github.com/jacobsa/fuse"
    18  	"github.com/jacobsa/fuse/fuseutil"
    19  	"github.com/jinzhu/copier"
    20  	"github.com/sirupsen/logrus"
    21  )
    22  
    23  var log = GetLogger("main")
    24  
    25  type Config struct {
    26  	// File system
    27  	MountOptions map[string]string
    28  	MountPoint   string
    29  
    30  	Cache    []string
    31  	DirMode  os.FileMode
    32  	FileMode os.FileMode
    33  	Uid      uint32
    34  	Gid      uint32
    35  
    36  	// S3
    37  	Endpoint       string
    38  	Region         string
    39  	RegionSet      bool
    40  	StorageClass   string
    41  	Profile        string
    42  	UseContentType bool
    43  	UseSSE         bool
    44  	UseKMS         bool
    45  	KMSKeyID       string
    46  	ACL            string
    47  
    48  	// Tuning
    49  	Cheap        bool
    50  	ExplicitDir  bool
    51  	StatCacheTTL time.Duration
    52  	TypeCacheTTL time.Duration
    53  
    54  	// Debugging
    55  	DebugFuse  bool
    56  	DebugS3    bool
    57  	Foreground bool
    58  }
    59  
    60  func Mount(
    61  	ctx context.Context,
    62  	bucketName string,
    63  	config *Config) (fs *Goofys, mfs *fuse.MountedFileSystem, err error) {
    64  
    65  	var flags FlagStorage
    66  	copier.Copy(&flags, config)
    67  
    68  	awsConfig := (&aws.Config{
    69  		Region: &flags.Region,
    70  		Logger: GetLogger("s3"),
    71  		//LogLevel: aws.LogLevel(aws.LogDebug),
    72  	}).WithHTTPClient(&http.Client{
    73  		Transport: &http.Transport{
    74  			Proxy: http.ProxyFromEnvironment,
    75  			DialContext: (&net.Dialer{
    76  				Timeout:   30 * time.Second,
    77  				KeepAlive: 30 * time.Second,
    78  				DualStack: true,
    79  			}).DialContext,
    80  			MaxIdleConns:          1000,
    81  			MaxIdleConnsPerHost:   1000,
    82  			IdleConnTimeout:       90 * time.Second,
    83  			TLSHandshakeTimeout:   10 * time.Second,
    84  			ExpectContinueTimeout: 10 * time.Second,
    85  		},
    86  	})
    87  
    88  	if len(flags.Profile) > 0 {
    89  		awsConfig.Credentials = credentials.NewSharedCredentials("", flags.Profile)
    90  	}
    91  
    92  	if len(flags.Endpoint) > 0 {
    93  		awsConfig.Endpoint = &flags.Endpoint
    94  	}
    95  
    96  	awsConfig.S3ForcePathStyle = aws.Bool(true)
    97  
    98  	fs = NewGoofys(ctx, bucketName, awsConfig, &flags)
    99  	if fs == nil {
   100  		err = fmt.Errorf("Mount: initialization failed")
   101  		return
   102  	}
   103  	server := fuseutil.NewFileSystemServer(fs)
   104  
   105  	fuseLog := GetLogger("fuse")
   106  
   107  	// Mount the file system.
   108  	mountCfg := &fuse.MountConfig{
   109  		FSName:                  bucketName,
   110  		Options:                 flags.MountOptions,
   111  		ErrorLogger:             GetStdLogger(NewLogger("fuse"), logrus.ErrorLevel),
   112  		DisableWritebackCaching: true,
   113  	}
   114  
   115  	if flags.DebugFuse {
   116  		fuseLog.Level = logrus.DebugLevel
   117  		log.Level = logrus.DebugLevel
   118  		mountCfg.DebugLogger = GetStdLogger(fuseLog, logrus.DebugLevel)
   119  	}
   120  
   121  	mfs, err = fuse.Mount(flags.MountPoint, server, mountCfg)
   122  	if err != nil {
   123  		err = fmt.Errorf("Mount: %v", err)
   124  		return
   125  	}
   126  
   127  	if len(flags.Cache) != 0 {
   128  		log.Infof("Starting catfs %v", flags.Cache)
   129  		catfs := exec.Command("catfs", flags.Cache...)
   130  		lvl := logrus.InfoLevel
   131  		if flags.DebugFuse {
   132  			lvl = logrus.DebugLevel
   133  			catfs.Env = append(catfs.Env, "RUST_LOG=debug")
   134  		} else {
   135  			catfs.Env = append(catfs.Env, "RUST_LOG=info")
   136  		}
   137  		catfsLog := GetLogger("catfs")
   138  		catfsLog.Formatter.(*LogHandle).Lvl = &lvl
   139  		catfs.Stderr = catfsLog.Writer()
   140  		err = catfs.Start()
   141  		if err != nil {
   142  			err = fmt.Errorf("Failed to start catfs: %v", err)
   143  
   144  			// sleep a bit otherwise can't unmount right away
   145  			time.Sleep(time.Second)
   146  			err2 := TryUnmount(flags.MountPoint)
   147  			if err2 != nil {
   148  				err = fmt.Errorf("%v. Failed to unmount: %v", err, err2)
   149  			}
   150  		}
   151  
   152  		go func() {
   153  			err := catfs.Wait()
   154  			log.Errorf("catfs exited: %v", err)
   155  
   156  			if err != nil {
   157  				// if catfs terminated cleanly, it
   158  				// should have unmounted this,
   159  				// otherwise we will do it ourselves
   160  				err2 := TryUnmount(flags.MountPointArg)
   161  				if err2 != nil {
   162  					log.Errorf("Failed to unmount: %v", err2)
   163  				}
   164  			}
   165  
   166  			if flags.MountPointArg != flags.MountPoint {
   167  				err2 := TryUnmount(flags.MountPoint)
   168  				if err2 != nil {
   169  					log.Errorf("Failed to unmount: %v", err2)
   170  				}
   171  			}
   172  
   173  			if err != nil {
   174  				os.Exit(1)
   175  			}
   176  		}()
   177  	}
   178  
   179  	return
   180  }