Documentation
¶
Overview ¶
Package muxfys is a pure Go library that lets you in-process temporarily fuse-mount remote file systems or object stores as a "filey" system. Currently only support for S3-like systems has been implemented.
It has high performance, and is easy to use with nothing else to install, and no root permissions needed (except to initially install/configure fuse: on old linux you may need to install fuse-utils, and for macOS you'll need to install osxfuse; for both you must ensure that 'user_allow_other' is set in /etc/fuse.conf or equivalent).
It allows "multiplexing": you can mount multiple different buckets (or sub directories of the same bucket) on the same local directory. This makes commands you want to run against the files in your buckets much simpler, eg. instead of mounting s3://publicbucket, s3://myinputbucket and s3://myoutputbucket to separate mount points and running: $ myexe -ref /mnt/publicbucket/refs/human/ref.fa -i /mnt/myinputbucket/xyz/123/
input.file > /mnt/myoutputbucket/xyz/123/output.file
You could multiplex the 3 buckets (at the desired paths) on to the directory you will work from and just run: $ myexe -ref ref.fa -i input.file > output.file
When using muxfys, you 1) mount, 2) do something that needs the files in your S3 bucket(s), 3) unmount. Then repeat 1-3 for other things that need data in your S3 buckets.
Usage ¶
import "github.com/VertebrateResequencing/wr/muxfys"
// fully manual target configuration
target1 := &muxfys.Target{
Target: "https://s3.amazonaws.com/mybucket/subdir",
Region: "us-east-1",
AccessKey: os.Getenv("AWS_ACCESS_KEY_ID"),
SecretKey: os.Getenv("AWS_SECRET_ACCESS_KEY"),
CacheDir: "/tmp/muxfys/cache",
Write: true,
}
// or read some configuration from standard AWS S3 config files and
// environment variables
target2 := &muxfys.Target{
CacheData: true,
}
target2.ReadEnvironment("default", "myotherbucket/another/subdir")
cfg := &muxfys.Config{
Mount: "/tmp/muxfys/mount",
CacheBase: "/tmp",
Retries: 3,
Verbose: true,
Targets: []*muxfys.Target{target, target2},
}
fs, err := muxfys.New(cfg)
if err != nil {
log.Fatalf("bad configuration: %s\n", err)
}
err = fs.Mount()
if err != nil {
log.Fatalf("could not mount: %s\n", err)
}
fs.UnmountOnDeath()
// read from & write to files in /tmp/muxfys/mount, which contains the
// contents of mybucket/subdir and myotherbucket/another/subdir; writes will
// get uploaded to mybucket/subdir when you Unmount()
err = fs.Unmount()
if err != nil {
log.Fatalf("could not unmount: %s\n", err)
}
logs := fs.Logs()
Index ¶
- func NewCachedFile(r *remote, remotePath, localPath string, attr *fuse.Attr, flags uint32, ...) nodefs.File
- func NewS3File(r *remote, path string, size uint64) nodefs.File
- func SetLogHandler(h log15.Handler)
- type CacheTracker
- func (c *CacheTracker) CacheDelete(path string)
- func (c *CacheTracker) CacheOverride(path string, iv Interval)
- func (c *CacheTracker) CacheRename(oldPath, newPath string)
- func (c *CacheTracker) CacheTruncate(path string, offset int64)
- func (c *CacheTracker) CacheWipe()
- func (c *CacheTracker) Cached(path string, iv Interval)
- func (c *CacheTracker) Uncached(path string, iv Interval) Intervals
- type CachedFile
- type Config
- type Interval
- type Intervals
- type MuxFys
- func (fs *MuxFys) Access(name string, mode uint32, context *fuse.Context) fuse.Status
- func (fs *MuxFys) Chmod(name string, mode uint32, context *fuse.Context) fuse.Status
- func (fs *MuxFys) Chown(name string, uid uint32, gid uint32, context *fuse.Context) fuse.Status
- func (fs *MuxFys) Create(name string, flags uint32, mode uint32, context *fuse.Context) (nodefs.File, fuse.Status)
- func (fs *MuxFys) GetAttr(name string, context *fuse.Context) (attr *fuse.Attr, status fuse.Status)
- func (fs *MuxFys) Logs() []string
- func (fs *MuxFys) Mkdir(name string, mode uint32, context *fuse.Context) fuse.Status
- func (fs *MuxFys) Mount() (err error)
- func (fs *MuxFys) OnMount(nodeFs *pathfs.PathNodeFs)
- func (fs *MuxFys) Open(name string, flags uint32, context *fuse.Context) (file nodefs.File, status fuse.Status)
- func (fs *MuxFys) OpenDir(name string, context *fuse.Context) ([]fuse.DirEntry, fuse.Status)
- func (fs *MuxFys) Readlink(name string, context *fuse.Context) (out string, status fuse.Status)
- func (fs *MuxFys) Rename(oldPath string, newPath string, context *fuse.Context) fuse.Status
- func (fs *MuxFys) Rmdir(name string, context *fuse.Context) fuse.Status
- func (fs *MuxFys) SetXAttr(name string, attr string, data []byte, flags int, context *fuse.Context) fuse.Status
- func (fs *MuxFys) StatFs(name string) *fuse.StatfsOut
- func (fs *MuxFys) Symlink(source string, dest string, context *fuse.Context) (status fuse.Status)
- func (fs *MuxFys) Truncate(name string, offset uint64, context *fuse.Context) fuse.Status
- func (fs *MuxFys) Unlink(name string, context *fuse.Context) fuse.Status
- func (fs *MuxFys) Unmount(doNotUpload ...bool) (err error)
- func (fs *MuxFys) UnmountOnDeath()
- func (fs *MuxFys) Utimens(name string, Atime *time.Time, Mtime *time.Time, context *fuse.Context) (status fuse.Status)
- type S3File
- type Target
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func NewCachedFile ¶
func NewCachedFile(r *remote, remotePath, localPath string, attr *fuse.Attr, flags uint32, logger log15.Logger) nodefs.File
NewCachedFile makes a CachedFile that reads each byte from remotePath only once, returning subsequent reads from and writing to localPath.
func NewS3File ¶
NewS3File creates a new S3File. For all the methods not yet implemented, fuse will get a not yet implemented error.
func SetLogHandler ¶
SetLogHandler defines how log messages (globally for this package) are logged. Logs are always retrievable as strings from individual MuxFys instances using MuxFys.Logs(), but otherwise by default are discarded. To have them logged somewhere as they are emitted, supply a github.com/inconshreveable/log15 Handler, eg. log15.StderrHandler to log everything to STDERR.
Types ¶
type CacheTracker ¶
CacheTracker struct is used to track what parts of which files have been cached.
func NewCacheTracker ¶
func NewCacheTracker() *CacheTracker
NewCacheTracker creates a new *CacheTracker.
func (*CacheTracker) CacheDelete ¶
func (c *CacheTracker) CacheDelete(path string)
CacheDelete should be used if you delete a cache file.
func (*CacheTracker) CacheOverride ¶
func (c *CacheTracker) CacheOverride(path string, iv Interval)
CacheOverride should be used if you do something like delete a cache file and then recreate it and cache some data inside it. This is the slightly more efficient alternative to calling Delete(path) followed by Cached(path, iv).
func (*CacheTracker) CacheRename ¶
func (c *CacheTracker) CacheRename(oldPath, newPath string)
CacheRename should be used if you rename a cache file on disk.
func (*CacheTracker) CacheTruncate ¶
func (c *CacheTracker) CacheTruncate(path string, offset int64)
CacheTruncate should be used to update the tracker if you truncate a cache file. The internal knowledge of what you have cached for that file will then be updated to exclude anything beyond the truncation point.
func (*CacheTracker) CacheWipe ¶
func (c *CacheTracker) CacheWipe()
CacheWipe should be used if you delete all your cache files.
func (*CacheTracker) Cached ¶
func (c *CacheTracker) Cached(path string, iv Interval)
Cached updates the tracker with what you have now cached. Once you have stored bytes 0..9 in /abs/path/to/sparse.file, you would call: Cached("/abs/path/to/sparse.file", NewInterval(0, 10)).
func (*CacheTracker) Uncached ¶
func (c *CacheTracker) Uncached(path string, iv Interval) Intervals
Uncached tells you what parts of a file in the given interval you haven't already cached (based on your prior Cached() calls). You would want to then cache the data in each of the returned intervals and call Cached() on each one afterwards.
type CachedFile ¶
CachedFile is used as a wrapper around a nodefs.loopbackFile, the only difference being that on Write it updates the given attr's Size, Mtime and Atime, and on Read it copies data from remote to local disk if not requested before.
func (*CachedFile) InnerFile ¶
func (f *CachedFile) InnerFile() nodefs.File
InnerFile returns the loopbackFile that deals with local files on disk.
func (*CachedFile) Read ¶
func (f *CachedFile) Read(buf []byte, offset int64) (fuse.ReadResult, fuse.Status)
Read checks to see if we've previously stored these bytes in our local cached file, and if so just defers to our InnerFile(). If not, gets the data from the remote object and stores it in the cache file.
type Config ¶
type Config struct {
// Mount is the local directory to mount on top of (muxfys will try to
// create this if it doesn't exist). If not supplied, defaults to the
// subdirectory "mnt" in the current working directory. Note that mounting
// will only succeed if the Mount directory either doesn't exist or is
// empty.
Mount string
// Retries is the number of times to automatically retry failed remote S3
// system requests. The default of 0 means don't retry; at least 3 is
// recommended.
Retries int
// CacheBase is the base directory that will be used to create any Target
// cache directories, when those Targets have CacheData true but CacheDir
// undefined. Defaults to the current working directory.
CacheBase string
// Verbose results in every remote request getting an entry in the output of
// Logs(). Errors always appear there.
Verbose bool
// Targets is a slice of Target, describing what you want to mount and
// allowing you to multiplex more than one bucket/ sub directory on to
// Mount. Only 1 of these Target can be writeable.
Targets []*Target
}
Config struct provides the configuration of a MuxFys.
type Interval ¶
Interval struct is used to describe something with a start and end. End must be greater than start.
func NewInterval ¶
NewInterval is a convenience for creating a new Interval when you have a length instead of an end.
func (*Interval) Merge ¶
Merge merges the supplied interval with this interval if they overlap or are adjacent. Returns true if a merge actually occurred.
func (*Interval) OverlapsOrAdjacent ¶
OverlapsOrAdjacent returns true if this interval overlaps with or is adjacent to the supplied one.
type Intervals ¶
type Intervals []Interval
Intervals type is a slice of Interval.
func (Intervals) Difference ¶
Difference returns any portions of iv that do not overlap with any of our intervals. Assumes that all of our intervals have been Merge()d in.
func (Intervals) Merge ¶
Merge adds another interval to this slice of intervals, merging with any prior intervals if it overlaps with or is adjacent to them. Returns the new slice of intervals, which have the property of not overlapping with or being adjacent to each other. They are also sorted by Start if Merge() was used to add all of them.
type MuxFys ¶
type MuxFys struct {
pathfs.FileSystem
log15.Logger
// contains filtered or unexported fields
}
MuxFys struct is the main filey system object.
func New ¶
New returns a MuxFys that you'll use to Mount() your S3 bucket(s), ensure you un-mount if killed by calling UnmountOnDeath(), then Unmount() when you're done. You might check Logs() afterwards. The other methods of MuxFys can be ignored in most cases.
func (*MuxFys) Create ¶
func (fs *MuxFys) Create(name string, flags uint32, mode uint32, context *fuse.Context) (nodefs.File, fuse.Status)
Create creates a new file. mode and context are not currently used. Only currently implemented for when configured with CacheData; the contents of the created file are only uploaded at Unmount() time.
func (*MuxFys) GetAttr ¶
GetAttr finds out about a given object, returning information from a permanent cache if possible. context is not currently used.
func (*MuxFys) Logs ¶
Logs returns messages generated while mounted; you might call it after Unmount() to see how things went. By default these will only be errors that occurred, but if this MuxFys was configured with Verbose on, it will also contain informational and warning messages. If the muxfys package was configured with a log Handler (see SetLogHandler()), these same messages would have been logged as they occurred.
func (*MuxFys) Mkdir ¶
Mkdir for a directory that doesn't exist yet only works whilst mounted in CacheData mode. neither mode nor context are currently used.
func (*MuxFys) Mount ¶
Mount carries out the mounting of your configured S3 bucket to your configured mount point. On return, the files in your bucket will be accessible. Once mounted, you can't mount again until you Unmount().
func (*MuxFys) OnMount ¶
func (fs *MuxFys) OnMount(nodeFs *pathfs.PathNodeFs)
OnMount prepares MuxFys for use once Mount() has been called.
func (*MuxFys) Open ¶
func (fs *MuxFys) Open(name string, flags uint32, context *fuse.Context) (file nodefs.File, status fuse.Status)
Open is what is called when any request to read a file is made. The file must already have been stat'ed (eg. with a GetAttr() call), or we report the file doesn't exist. context is not currently used. If CacheData has been configured, we defer to openCached(). Otherwise the real implementation is in S3File.
func (*MuxFys) OpenDir ¶
OpenDir gets the contents of the given directory for eg. `ls` purposes. It also caches the attributes of all the files within. context is not currently used.
func (*MuxFys) Readlink ¶
Readlink returns the destination of a symbolic link that was created with Symlink(). context is not currently used.
func (*MuxFys) Rename ¶
Rename only works where oldPath is found in the writeable remote. For files, first remotely copies oldPath to newPath (ignoring any local changes to oldPath), renames any local cached (and possibly modified) copy of oldPath to newPath, and finally deletes the remote oldPath; if oldPath had been modified, its changes will only be uploaded to newPath at Unmount() time. For directories, is only capable of renaming directories you have created whilst mounted. context is not currently used.
func (*MuxFys) Rmdir ¶
Rmdir only works for directories you have created whilst mounted in CacheData mode. context is not currently used.
func (*MuxFys) SetXAttr ¶
func (fs *MuxFys) SetXAttr(name string, attr string, data []byte, flags int, context *fuse.Context) fuse.Status
SetXAttr is ignored.
func (*MuxFys) StatFs ¶
StatFs returns a constant (faked) set of details describing a very large file system.
func (*MuxFys) Symlink ¶
Symlink creates a symbolic link. Only implemented for temporary use when configured with CacheData: you can create and use symlinks but they don't get uploaded. context is not currently used.
func (*MuxFys) Truncate ¶
Truncate truncates any local cached copy of the file. Only currently implemented for when configured with CacheData; the results of the Truncate are only uploaded at Unmount() time. If offset is > size of file, does nothing and returns OK. context is not currently used.
func (*MuxFys) Unlink ¶
Unlink deletes a file from the remote S3 bucket, as well as any locally cached copy. context is not currently used.
func (*MuxFys) Unmount ¶
Unmount must be called when you're done reading from/ writing to your bucket. Be sure to close any open filehandles before hand! It's a good idea to defer this after calling Mount(), and possibly also call UnmountOnDeath(). In CacheData mode, it is only at Unmount() that any files you created or altered get uploaded, so this may take some time. You can optionally supply a bool which if true prevents any uploads. If a target was not configured with a specific CacheDir but CacheData was true, the CacheDir will be deleted.
func (*MuxFys) UnmountOnDeath ¶
func (fs *MuxFys) UnmountOnDeath()
UnmountOnDeath captures SIGINT (ctrl-c) and SIGTERM (kill) signals, then calls Unmount() before calling os.Exit(1 if the unmount worked, 2 otherwise) to terminate your program. Manually calling Unmount() after this cancels the signal capture. This does NOT block.
func (*MuxFys) Utimens ¶
func (fs *MuxFys) Utimens(name string, Atime *time.Time, Mtime *time.Time, context *fuse.Context) (status fuse.Status)
Utimens only functions when configured with CacheData and the file is already in the cache; otherwise ignored. This only gets called by direct operations like os.Chtimes() (that don't first Open()/Create() the file). context is not currently used.
type S3File ¶
S3File struct is muxfys' implementation of pathfs.File, providing read/write operations on files in the remote bucket (when we're not doing any local caching of data).
func (*S3File) Fsync ¶
Fsync always returns OK as opposed to "not imlemented" so that write-sync- write works.
type Target ¶
type Target struct {
// The full URL of your bucket and possible sub-path, eg.
// https://cog.domain.com/bucket/subpath. For performance reasons, you
// should specify the deepest subpath that holds all your files. This will
// be set for you by a call to ReadEnvironment().
Target string
// Region is optional if you need to use a specific region. This can be set
// for you by a call to ReadEnvironment().
Region string
// AccessKey and SecretKey can be set for you by calling ReadEnvironment().
AccessKey string
SecretKey string
// CacheData enables caching of remote files that you read locally on disk.
// Writes will also be staged on local disk prior to upload.
CacheData bool
// CacheDir is the directory used to cache data if CacheData is true.
// (muxfys will try to create this if it doesn't exist). If not supplied
// when CacheData is true, muxfys will create a unique temporary directory
// in the CacheBase directory of the containing Config (these get
// automatically deleted on Unmount() - specified CacheDirs do not).
// Defining this makes CacheData be treated as true.
CacheDir string
// Write enables write operations in the mount. Only set true if you know
// you really need to write. Since writing currently requires caching of
// data, CacheData will be treated as true.
Write bool
}
Target struct provides details of the remote target (S3 bucket) you wish to mount, and particulars about caching and writing for this target.
func (*Target) CreateRemote ¶
func (t *Target) CreateRemote(cacheBase string, maxAttempts int, logger log15.Logger) (r *remote, err error)
CreateRemote uses the configured details of the Target to create a *remote, used internally by MuxFys.New().
func (*Target) ReadEnvironment ¶
ReadEnvironment sets Target, AccessKey and SecretKey and possibly Region. It determines these by looking primarily at the given profile section of ~/.s3cfg (s3cmd's config file). If profile is an empty string, it comes from $AWS_DEFAULT_PROFILE or $AWS_PROFILE or defaults to "default". If ~/.s3cfg doesn't exist or isn't fully specified, missing values will be taken from the file pointed to by $AWS_SHARED_CREDENTIALS_FILE, or ~/.aws/credentials (in the AWS CLI format) if that is not set. If this file also doesn't exist, ~/.awssecret (in the format used by s3fs) is used instead. AccessKey and SecretKey values will always preferably come from $AWS_ACCESS_KEY_ID and $AWS_SECRET_ACCESS_KEY respectively, if those are set. If no config file specified host_base, the default domain used is s3.amazonaws.com. Region is set by the $AWS_DEFAULT_REGION environment variable, or if that is not set, by checking the file pointed to by $AWS_CONFIG_FILE (~/.aws/config if unset). To allow the use of a single configuration file, users can create a non- standard file that specifies all relevant options: use_https, host_base, region, access_key (or aws_access_key_id) and secret_key (or aws_secret_access_key) (saved in any of the files except ~/.awssecret). The path argument should at least be the bucket name, but ideally should also specify the deepest subpath that holds all the files that need to be accessed. Because reading from a public s3.amazonaws.com bucket requires no credentials, no error is raised on failure to find any values in the environment when profile is supplied as an empty string.