github.com/t2y/goofys@v0.19.1-0.20190123053037-27053313e616/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  	AccessKey      string
    42  	SecretKey      string
    43  	Profile        string
    44  	UseContentType bool
    45  	UseSSE         bool
    46  	UseKMS         bool
    47  	KMSKeyID       string
    48  	ACL            string
    49  
    50  	// Tuning
    51  	Cheap        bool
    52  	ExplicitDir  bool
    53  	StatCacheTTL time.Duration
    54  	TypeCacheTTL time.Duration
    55  	HTTPTimeout  time.Duration
    56  
    57  	// Debugging
    58  	DebugFuse  bool
    59  	DebugS3    bool
    60  	Foreground bool
    61  }
    62  
    63  func Mount(
    64  	ctx context.Context,
    65  	bucketName string,
    66  	config *Config) (fs *Goofys, mfs *fuse.MountedFileSystem, err error) {
    67  
    68  	var flags FlagStorage
    69  	copier.Copy(&flags, config)
    70  
    71  	awsConfig := (&aws.Config{
    72  		Region: &flags.Region,
    73  		Logger: GetLogger("s3"),
    74  		//LogLevel: aws.LogLevel(aws.LogDebug),
    75  	}).WithHTTPClient(&http.Client{
    76  		Transport: &http.Transport{
    77  			Proxy: http.ProxyFromEnvironment,
    78  			DialContext: (&net.Dialer{
    79  				Timeout:   30 * time.Second,
    80  				KeepAlive: 30 * time.Second,
    81  				DualStack: true,
    82  			}).DialContext,
    83  			MaxIdleConns:          1000,
    84  			MaxIdleConnsPerHost:   1000,
    85  			IdleConnTimeout:       90 * time.Second,
    86  			TLSHandshakeTimeout:   10 * time.Second,
    87  			ExpectContinueTimeout: 10 * time.Second,
    88  		},
    89  		Timeout: flags.HTTPTimeout,
    90  	})
    91  
    92  	if config.AccessKey != "" {
    93  		awsConfig.Credentials = credentials.NewStaticCredentials(config.AccessKey, config.SecretKey, "")
    94  	} else if len(flags.Profile) > 0 {
    95  		awsConfig.Credentials = credentials.NewSharedCredentials("", flags.Profile)
    96  	}
    97  
    98  	if len(flags.Endpoint) > 0 {
    99  		awsConfig.Endpoint = &flags.Endpoint
   100  	}
   101  
   102  	awsConfig.S3ForcePathStyle = aws.Bool(true)
   103  
   104  	fs = NewGoofys(ctx, bucketName, awsConfig, &flags)
   105  	if fs == nil {
   106  		err = fmt.Errorf("Mount: initialization failed")
   107  		return
   108  	}
   109  	server := fuseutil.NewFileSystemServer(fs)
   110  
   111  	fuseLog := GetLogger("fuse")
   112  
   113  	// Mount the file system.
   114  	mountCfg := &fuse.MountConfig{
   115  		FSName:                  bucketName,
   116  		Options:                 flags.MountOptions,
   117  		ErrorLogger:             GetStdLogger(NewLogger("fuse"), logrus.ErrorLevel),
   118  		DisableWritebackCaching: true,
   119  	}
   120  
   121  	if flags.DebugFuse {
   122  		fuseLog.Level = logrus.DebugLevel
   123  		log.Level = logrus.DebugLevel
   124  		mountCfg.DebugLogger = GetStdLogger(fuseLog, logrus.DebugLevel)
   125  	}
   126  
   127  	mfs, err = fuse.Mount(flags.MountPoint, server, mountCfg)
   128  	if err != nil {
   129  		err = fmt.Errorf("Mount: %v", err)
   130  		return
   131  	}
   132  
   133  	if len(flags.Cache) != 0 {
   134  		log.Infof("Starting catfs %v", flags.Cache)
   135  		catfs := exec.Command("catfs", flags.Cache...)
   136  		lvl := logrus.InfoLevel
   137  		if flags.DebugFuse {
   138  			lvl = logrus.DebugLevel
   139  			catfs.Env = append(catfs.Env, "RUST_LOG=debug")
   140  		} else {
   141  			catfs.Env = append(catfs.Env, "RUST_LOG=info")
   142  		}
   143  		catfsLog := GetLogger("catfs")
   144  		catfsLog.Formatter.(*LogHandle).Lvl = &lvl
   145  		catfs.Stderr = catfsLog.Writer()
   146  		err = catfs.Start()
   147  		if err != nil {
   148  			err = fmt.Errorf("Failed to start catfs: %v", err)
   149  
   150  			// sleep a bit otherwise can't unmount right away
   151  			time.Sleep(time.Second)
   152  			err2 := TryUnmount(flags.MountPoint)
   153  			if err2 != nil {
   154  				err = fmt.Errorf("%v. Failed to unmount: %v", err, err2)
   155  			}
   156  		}
   157  
   158  		go func() {
   159  			err := catfs.Wait()
   160  			log.Errorf("catfs exited: %v", err)
   161  
   162  			if err != nil {
   163  				// if catfs terminated cleanly, it
   164  				// should have unmounted this,
   165  				// otherwise we will do it ourselves
   166  				err2 := TryUnmount(flags.MountPointArg)
   167  				if err2 != nil {
   168  					log.Errorf("Failed to unmount: %v", err2)
   169  				}
   170  			}
   171  
   172  			if flags.MountPointArg != flags.MountPoint {
   173  				err2 := TryUnmount(flags.MountPoint)
   174  				if err2 != nil {
   175  					log.Errorf("Failed to unmount: %v", err2)
   176  				}
   177  			}
   178  
   179  			if err != nil {
   180  				os.Exit(1)
   181  			}
   182  		}()
   183  	}
   184  
   185  	return
   186  }
   187  
   188  // expose Goofys related functions and types for extending and mounting elsewhere
   189  var (
   190  	GetStdLogger      = internal.GetStdLogger
   191  	InitLoggers       = internal.InitLoggers
   192  	MassageMountFlags = internal.MassageMountFlags
   193  	GetLogger         = internal.GetLogger
   194  	NewGoofys         = internal.NewGoofys
   195  	NewLogger         = internal.NewLogger
   196  	TryUnmount        = internal.TryUnmount
   197  	MyUserAndGroup    = internal.MyUserAndGroup
   198  )
   199  
   200  type (
   201  	Goofys      = internal.Goofys
   202  	FlagStorage = internal.FlagStorage
   203  	LogHandle   = internal.LogHandle
   204  )