From a4f53875bc15d690355aa2f153d6dbd1e204dd26 Mon Sep 17 00:00:00 2001 From: Barak Michener Date: Sat, 31 Mar 2018 15:11:02 -0700 Subject: [PATCH] finish basic fs commands, stub out file on server side --- README.md | 2 +- filesystem.go | 210 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- fs/local.go | 2 +- fs_file.go | 70 ++++++++++++++++++++ request.go | 29 ++++---- 5 files changed, 294 insertions(+), 19 deletions(-) create mode 100644 fs_file.go diff --git a/README.md b/README.md index 54e6517..2c3298b 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ It's great to have a consistent environment in containers, and it's great to hav It would be great if your live development working directory could be mounted into a running pod on the powerful metal in the cloud. Plus, it would obviate the need for workaround services such as [ngrok](https://ngrok.com) to share a running WIP instance, as it would have a valid service on the dev cluster, complete with Ingress resources and everything. Plus, it's running in-cluster; so all the configurations and access controls and service discoveries are available to your dev instance. With the absolute latest, WIP code from your laptop. -Use it in tandem with automatically refreshing dev environments -- JS auto-reloaders for frontend devs, [entr](https://entrproject.org) for general reloads, or any other tooling you like. +Use it in tandem with automatically refreshing dev environments -- JS auto-reloaders for frontend devs, [entr](http://entrproject.org) for general reloads, or any other tooling you like. Kubelwagen is a sidecar ([hah](https://en.wikipedia.org/wiki/Volkswagen_K%C3%BCbelwagen)) container that provides a FUSE directory to the running pod that is mounted in from a client connecting in over an HTTPS websocket. diff --git a/filesystem.go b/filesystem.go index e045ade..2d18cfd 100644 --- a/filesystem.go +++ b/filesystem.go @@ -1,7 +1,10 @@ package kubelwagen import ( + "time" + "github.com/hanwen/go-fuse/fuse" + "github.com/hanwen/go-fuse/fuse/nodefs" "github.com/hanwen/go-fuse/fuse/pathfs" "github.com/sirupsen/logrus" ) @@ -46,6 +49,9 @@ func (fs *WsFs) getResponse(r *Request) (Response, bool) { response: c, } resp, ok := <-c + if !ok { + logrus.Errorln("Response to request channel closed") + } return resp, ok } @@ -56,7 +62,6 @@ func (fs *WsFs) OpenDir(name string, context *fuse.Context) ([]fuse.DirEntry, fu } resp, ok := fs.getResponse(&r) if !ok { - logrus.Errorln("Response to request channel closed") return fs.FileSystem.OpenDir(name, context) } return resp.Dirents, resp.Code @@ -69,7 +74,6 @@ func (fs *WsFs) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.St } resp, ok := fs.getResponse(&r) if !ok { - logrus.Errorln("Response to request channel closed") return fs.FileSystem.GetAttr(name, context) } return resp.Stat, resp.Code @@ -82,9 +86,207 @@ func (fs *WsFs) StatFs(name string) *fuse.StatfsOut { } resp, ok := fs.getResponse(&r) if !ok { - logrus.Errorln("Response to request channel closed") return fs.FileSystem.StatFs(name) } return resp.Statfs - +} + +func (fs *WsFs) GetXAttr(name string, attr string, context *fuse.Context) ([]byte, fuse.Status) { + return nil, fuse.ENOATTR +} + +func (fs *WsFs) SetXAttr(name string, attr string, data []byte, flags int, context *fuse.Context) fuse.Status { + return fuse.ENOSYS +} + +func (fs *WsFs) ListXAttr(name string, context *fuse.Context) ([]string, fuse.Status) { + return nil, fuse.ENOSYS +} + +func (fs *WsFs) RemoveXAttr(name string, attr string, context *fuse.Context) fuse.Status { + return fuse.ENOSYS +} + +func (fs *WsFs) Readlink(name string, context *fuse.Context) (string, fuse.Status) { + r := Request{ + Method: MethodReadLink, + Path: name, + } + resp, ok := fs.getResponse(&r) + if !ok { + return "", fuse.ENOSYS + } + return resp.LinkStr, resp.Code +} + +func (fs *WsFs) Mknod(name string, mode uint32, dev uint32, context *fuse.Context) fuse.Status { + r := Request{ + Method: MethodMknod, + Path: name, + Mode: mode, + Dev: int32(dev), + } + resp, ok := fs.getResponse(&r) + if !ok { + return fuse.ENOSYS + } + return resp.Code +} + +func (fs *WsFs) Mkdir(name string, mode uint32, context *fuse.Context) fuse.Status { + r := Request{ + Method: MethodMkdir, + Path: name, + Mode: mode, + } + resp, ok := fs.getResponse(&r) + if !ok { + return fuse.ENOSYS + } + return resp.Code +} + +func (fs *WsFs) Unlink(name string, context *fuse.Context) (code fuse.Status) { + r := Request{ + Method: MethodUnlink, + Path: name, + } + resp, ok := fs.getResponse(&r) + if !ok { + return fuse.ENOSYS + } + return resp.Code +} + +func (fs *WsFs) Rmdir(name string, context *fuse.Context) (code fuse.Status) { + r := Request{ + Method: MethodRmdir, + Path: name, + } + resp, ok := fs.getResponse(&r) + if !ok { + return fuse.ENOSYS + } + return resp.Code +} + +func (fs *WsFs) Symlink(value string, linkName string, context *fuse.Context) (code fuse.Status) { + r := Request{ + Method: MethodSymlink, + Path: linkName, + NewPath: value, + } + resp, ok := fs.getResponse(&r) + if !ok { + return fuse.ENOSYS + } + return resp.Code +} + +func (fs *WsFs) Rename(oldName string, newName string, context *fuse.Context) (code fuse.Status) { + r := Request{ + Method: MethodRename, + Path: oldName, + NewPath: newName, + } + resp, ok := fs.getResponse(&r) + if !ok { + return fuse.ENOSYS + } + return resp.Code +} + +func (fs *WsFs) Link(oldName string, newName string, context *fuse.Context) (code fuse.Status) { + r := Request{ + Method: MethodLink, + Path: oldName, + NewPath: newName, + } + resp, ok := fs.getResponse(&r) + if !ok { + return fuse.ENOSYS + } + return resp.Code +} + +func (fs *WsFs) Chmod(name string, mode uint32, context *fuse.Context) (code fuse.Status) { + r := Request{ + Method: MethodChmod, + Path: name, + Mode: mode, + } + resp, ok := fs.getResponse(&r) + if !ok { + return fuse.ENOSYS + } + return resp.Code +} + +func (fs *WsFs) Chown(name string, uid uint32, gid uint32, context *fuse.Context) (code fuse.Status) { + r := Request{ + Method: MethodChown, + Path: name, + UID: uid, + GID: gid, + } + resp, ok := fs.getResponse(&r) + if !ok { + return fuse.ENOSYS + } + return resp.Code +} + +func (fs *WsFs) Truncate(name string, offset uint64, context *fuse.Context) (code fuse.Status) { + r := Request{ + Method: MethodChown, + Path: name, + Offset: offset, + } + resp, ok := fs.getResponse(&r) + if !ok { + return fuse.ENOSYS + } + return resp.Code +} + +func (fs *WsFs) Access(name string, mode uint32, context *fuse.Context) (code fuse.Status) { + r := Request{ + Method: MethodAccess, + Path: name, + Mode: mode, + } + resp, ok := fs.getResponse(&r) + if !ok { + return fuse.ENOSYS + } + return resp.Code +} + +func (fs *WsFs) Utimens(name string, Atime *time.Time, Mtime *time.Time, context *fuse.Context) (code fuse.Status) { + return fuse.ENOSYS +} + +func (fs *WsFs) Open(name string, flags uint32, context *fuse.Context) (file nodefs.File, code fuse.Status) { + r := Request{ + Method: MethodOpen, + Flags: flags, + } + resp, ok := fs.getResponse(&r) + if !ok { + return nil, fuse.ENOSYS + } + return newWsFsFile(*resp.FileHandle, fs), resp.Code +} + +func (fs *WsFs) Create(name string, flags uint32, mode uint32, context *fuse.Context) (file nodefs.File, code fuse.Status) { + r := Request{ + Method: MethodCreate, + Flags: flags, + Mode: mode, + } + resp, ok := fs.getResponse(&r) + if !ok { + return nil, fuse.ENOSYS + } + return newWsFsFile(*resp.FileHandle, fs), resp.Code } diff --git a/fs/local.go b/fs/local.go index 3516898..06ced99 100644 --- a/fs/local.go +++ b/fs/local.go @@ -36,7 +36,7 @@ func (fs *LocalFs) Handle(r *kubelwagen.Request) *kubelwagen.Response { case kubelwagen.MethodChown: return fs.serveFromErr(r, os.Chown(fs.getPath(r), int(r.UID), int(r.GID))) case kubelwagen.MethodTruncate: - return fs.serveFromErr(r, os.Truncate(fs.getPath(r), r.Offset)) + return fs.serveFromErr(r, os.Truncate(fs.getPath(r), int64(r.Offset))) case kubelwagen.MethodMknod: return fs.serveFromErr(r, syscall.Mknod(fs.getPath(r), r.Mode, int(r.Dev))) case kubelwagen.MethodMkdir: diff --git a/fs_file.go b/fs_file.go new file mode 100644 index 0000000..14422f9 --- /dev/null +++ b/fs_file.go @@ -0,0 +1,70 @@ +package kubelwagen + +import ( + "time" + + "github.com/hanwen/go-fuse/fuse" + "github.com/hanwen/go-fuse/fuse/nodefs" +) + +type WsFsFile struct { + nodefs.File + h int + fs *WsFs +} + +func newWsFsFile(handle int, fs *WsFs) *WsFsFile { + return &WsFsFile{ + File: nodefs.NewDefaultFile(), + h: handle, + fs: fs, + } +} +func (f *WsFsFile) String() string { + return "WsFsFile" +} + +func (f *WsFsFile) Read(buf []byte, off int64) (fuse.ReadResult, fuse.Status) { + return nil, fuse.ENOSYS +} + +func (f *WsFsFile) Write(data []byte, off int64) (uint32, fuse.Status) { + return 0, fuse.ENOSYS +} + +func (f *WsFsFile) Flock(flags int) fuse.Status { return fuse.ENOSYS } +func (f *WsFsFile) Flush() fuse.Status { + return fuse.OK +} + +func (f *WsFsFile) Release() { + +} + +func (f *WsFsFile) GetAttr(*fuse.Attr) fuse.Status { + return fuse.ENOSYS +} + +func (f *WsFsFile) Fsync(flags int) (code fuse.Status) { + return fuse.ENOSYS +} + +func (f *WsFsFile) Utimens(atime *time.Time, mtime *time.Time) fuse.Status { + return fuse.ENOSYS +} + +func (f *WsFsFile) Truncate(size uint64) fuse.Status { + return fuse.ENOSYS +} + +func (f *WsFsFile) Chown(uid uint32, gid uint32) fuse.Status { + return fuse.ENOSYS +} + +func (f *WsFsFile) Chmod(perms uint32) fuse.Status { + return fuse.ENOSYS +} + +func (f *WsFsFile) Allocate(off uint64, size uint64, mode uint32) (code fuse.Status) { + return fuse.ENOSYS +} diff --git a/request.go b/request.go index bb39bd5..5596017 100644 --- a/request.go +++ b/request.go @@ -21,6 +21,8 @@ const ( MethodLink MethodReadLink MethodAccess + MethodOpen + MethodCreate ) type Request struct { @@ -28,12 +30,12 @@ type Request struct { Method Method `json:"method"` Path string `json:"path"` Mode uint32 - UID int32 - GID int32 - Size int32 + UID uint32 + GID uint32 + Size uint32 Dev int32 - Flags int32 - Offset int64 + Flags uint32 + Offset uint64 NewPath string `json:"newpath,omitempty"` Attr string `json:"attr,omitempty"` Data []byte `json:"data,omitempty"` @@ -45,12 +47,13 @@ type RequestCallback struct { } type Response struct { - ID int `json:"id"` - Code fuse.Status `json:"status"` - Data []byte `json:"data,omitempty"` - Stat *fuse.Attr `json:"stat,omitempty"` - Attrs []string `json:"attrs,omitempty"` - Dirents []fuse.DirEntry `json:"dirents,omitempty"` - LinkStr string `json:"linkstr,omitempty"` - Statfs *fuse.StatfsOut `json:"statfs,omitempty"` + ID int `json:"id"` + Code fuse.Status `json:"status"` + Data []byte `json:"data,omitempty"` + Stat *fuse.Attr `json:"stat,omitempty"` + Attrs []string `json:"attrs,omitempty"` + Dirents []fuse.DirEntry `json:"dirents,omitempty"` + LinkStr string `json:"linkstr,omitempty"` + Statfs *fuse.StatfsOut `json:"statfs,omitempty"` + FileHandle *int `json:"filehandle,omitempty"` }