finish basic fs commands, stub out file on server side

This commit is contained in:
Barak Michener 2018-03-31 15:11:02 -07:00
parent 8a91fdcb4e
commit a4f53875bc
5 changed files with 294 additions and 19 deletions

View file

@ -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.

View file

@ -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
}

View file

@ -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:

70
fs_file.go Normal file
View file

@ -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
}

View file

@ -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"`
}