Did a TON of shit
This commit is contained in:
225
main.go
225
main.go
@@ -4,6 +4,11 @@ import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"context"
|
||||
"os/user"
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
|
||||
"github.com/knusbaum/go9p"
|
||||
"github.com/knusbaum/go9p/fs"
|
||||
"github.com/knusbaum/go9p/proto"
|
||||
@@ -12,70 +17,101 @@ import (
|
||||
"github.com/docker/docker/client"
|
||||
)
|
||||
|
||||
///
|
||||
///
|
||||
/// Dynamic Tree Implementation
|
||||
///
|
||||
///
|
||||
|
||||
type NewStat func (name, uid, gid string, mode uint32) *proto.Stat
|
||||
|
||||
type NodeGenerator func (t Tree) []fs.FSNode;
|
||||
type Mappable interface {
|
||||
MapFS(t *Tree) []fs.FSNode
|
||||
}
|
||||
|
||||
type NodeGenerator func (t *Tree) []fs.FSNode;
|
||||
|
||||
func (ng NodeGenerator) MapFS(t *Tree) []fs.FSNode { return ng(t) };
|
||||
|
||||
type Tree struct {
|
||||
tStat proto.Stat
|
||||
tParent fs.Dir
|
||||
//tcache []fs.FSNode
|
||||
NodeNS NewStat
|
||||
NodeGen NodeGenerator
|
||||
//NodeGen NodeGenerator
|
||||
NodeGen Mappable
|
||||
}
|
||||
|
||||
func (t Tree) Stat() proto.Stat { return t.tStat }
|
||||
func (t *Tree) Stat() proto.Stat { return t.tStat }
|
||||
|
||||
func (t Tree) WriteStat(s *proto.Stat) error { return errors.New("attributes are read only") }
|
||||
func (t *Tree) WriteStat(s *proto.Stat) error { return errors.New("attributes are read only") }
|
||||
|
||||
func (t Tree) SetParent(p fs.Dir) {}
|
||||
func (t *Tree) SetParent(p fs.Dir) {}
|
||||
|
||||
func (t Tree) Parent() fs.Dir { return t.tParent }
|
||||
func (t *Tree) Parent() fs.Dir { return t.tParent }
|
||||
|
||||
func (t Tree) Children() map[string]fs.FSNode {
|
||||
func (t *Tree) Children() map[string]fs.FSNode {
|
||||
ret := make(map[string]fs.FSNode)
|
||||
for _, n := range t.NodeGen(t) {
|
||||
for _, n := range t.NodeGen.MapFS(t) { //t.tcache { //t.NodeGen.MapFS(t) { //t.NodeGen(t) {
|
||||
ret[n.Stat().Name] = n
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func NewTree(s *proto.Stat, p fs.Dir, ns NewStat, ng NodeGenerator) Tree {
|
||||
t := Tree{
|
||||
//func (t *Tree) Update() {
|
||||
// t.tcache = t.NodeGen.MapFS(t)
|
||||
//}
|
||||
|
||||
//func NewTree(s *proto.Stat, p fs.Dir, ns NewStat, ng NodeGenerator) Tree {
|
||||
func NewTree(s *proto.Stat, p fs.Dir, ns NewStat, ng Mappable) *Tree {
|
||||
t := &Tree{
|
||||
tStat: *s,
|
||||
tParent: p,
|
||||
//tcache: make([]fs.FSNode, 0),
|
||||
NodeNS: ns,
|
||||
NodeGen: ng,
|
||||
}
|
||||
t.tStat.Mode |= proto.DMDIR
|
||||
t.tStat.Qid.Qtype = uint8(t.tStat.Mode >> 24)
|
||||
//t.Update()
|
||||
return t
|
||||
}
|
||||
|
||||
/*
|
||||
type TestMFS struct {
|
||||
a int
|
||||
// This is just a helper for merging Mappables/NodeGenerators together
|
||||
// Allows for making distinct node generators for sections of a Dynamic Tree
|
||||
// without much hassle
|
||||
func ConcatMapFS(m ...Mappable) NodeGenerator {
|
||||
return func(t *Tree) []fs.FSNode {
|
||||
ret := make([]fs.FSNode, 0)
|
||||
|
||||
for _, n := range m {
|
||||
ret = append(ret, n.MapFS(t)...)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
}
|
||||
|
||||
func NewTestMFS(a int) *TestMFS {
|
||||
return &TestMFS{a}
|
||||
}
|
||||
*/
|
||||
|
||||
///
|
||||
///
|
||||
/// DockerFS Implementation
|
||||
///
|
||||
///
|
||||
|
||||
type ContainerNode dtypes.Container
|
||||
|
||||
func (cn ContainerNode) ContainerToFS(t Tree) []fs.FSNode {
|
||||
func (cn ContainerNode) MapFS(t *Tree) []fs.FSNode {
|
||||
hnewstat := func(name string) *proto.Stat { return t.NodeNS(name, t.Stat().Uid, t.Stat().Gid, 0444) }
|
||||
|
||||
ID_Node := fs.NewStaticFile(hnewstat("ID"), []byte(cn.ID))
|
||||
|
||||
Names_Node_ng := func(t Tree) []fs.FSNode {
|
||||
Names_Node_ng := NodeGenerator(func(t *Tree) []fs.FSNode {
|
||||
ret := make([]fs.FSNode, 0)
|
||||
for i, n := range cn.Names {
|
||||
ret = append(ret, fs.NewStaticFile(hnewstat(strconv.Itoa(i)), []byte(n)))
|
||||
}
|
||||
return ret
|
||||
}
|
||||
})
|
||||
Names_Node := NewTree(t.NodeNS("Names", t.Stat().Uid, t.Stat().Gid, 0777), t, t.NodeNS, Names_Node_ng)
|
||||
|
||||
Image_Node := fs.NewStaticFile(hnewstat("Image"), []byte(cn.Image))
|
||||
@@ -86,37 +122,156 @@ func (cn ContainerNode) ContainerToFS(t Tree) []fs.FSNode {
|
||||
|
||||
Created_Node := fs.NewStaticFile(hnewstat("Created"), []byte(strconv.Itoa(int(cn.Created))))
|
||||
|
||||
|
||||
return []fs.FSNode{ID_Node, Names_Node, Image_Node, ImageID_Node, Command_Node, Created_Node}
|
||||
}
|
||||
|
||||
type ClientNode struct {
|
||||
*client.Client
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
// Alot of this was hacked together with ideas from fs.DynamicFile
|
||||
type ContainerLogsNode struct {
|
||||
nStat proto.Stat
|
||||
nParent fs.Dir
|
||||
sync.RWMutex
|
||||
fidContent map[uint64]io.ReadCloser
|
||||
cli *ClientNode
|
||||
containerNode ContainerNode
|
||||
}
|
||||
|
||||
func (n *ContainerLogsNode) Stat() proto.Stat { return n.nStat }
|
||||
func (n *ContainerLogsNode) WriteStat(s *proto.Stat) error { return errors.New("attributes are read only") }
|
||||
func (n *ContainerLogsNode) SetParent(p fs.Dir) {}
|
||||
func (n *ContainerLogsNode) Parent() fs.Dir { return n.nParent }
|
||||
func (n *ContainerLogsNode) Open(fid uint64, omode proto.Mode) error {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
out, err := n.cli.ContainerLogs(
|
||||
//n.cli.ctx, n.nParent.Stat().Name,
|
||||
n.cli.ctx, n.containerNode.ID,
|
||||
// Tail is set to 0, but a default 1024 lines is planned
|
||||
// Follow is set to true so the file can be read with a
|
||||
// stream of the latest logs
|
||||
// Options structs will later just be incorporated as
|
||||
// part of either the ClientNode or ContainerNode with
|
||||
// a ctl file for changing the options
|
||||
containertypes.LogsOptions{ShowStdout: true, ShowStderr: true, Tail: "0", Follow: true},
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
n.fidContent[fid] = out
|
||||
return nil
|
||||
}
|
||||
func (n *ContainerLogsNode) Read(fid uint64, offset uint64, count uint64) ([]byte, error) {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
bs := make([]byte, count)
|
||||
switch _, err := n.fidContent[fid].Read(bs); err {
|
||||
case nil:
|
||||
return bs, nil
|
||||
case io.EOF:
|
||||
return []byte{}, nil
|
||||
default:
|
||||
println(err.Error())
|
||||
return []byte{}, err
|
||||
}
|
||||
}
|
||||
func (n *ContainerLogsNode) Write(fid uint64, offset uint64, data []byte) (uint32, error) {
|
||||
return 0, errors.New("Cannot write to file.")
|
||||
}
|
||||
func (n *ContainerLogsNode) Close(fid uint64) error { delete(n.fidContent, fid); return nil }
|
||||
|
||||
|
||||
// This wasn't really that clever, idk maybe we'll see
|
||||
/*
|
||||
func (n *ContainerLogsNode) MapFS(t *Tree) []fs.FSNode {
|
||||
n.nStat = *t.NodeNS("Logs", t.Stat().Uid, t.Stat().Gid, 0777)
|
||||
n.nParent = t
|
||||
n.fidContent = make(map[uint64]io.ReadCloser)
|
||||
return []fs.FSNode{n}
|
||||
}
|
||||
*/
|
||||
|
||||
//func (n *ContainerLogsNode) MapFS(t *Tree)
|
||||
|
||||
func NewContainerLogsNode(s *proto.Stat, p fs.Dir, cliNode *ClientNode, containerNode ContainerNode) *ContainerLogsNode {
|
||||
return &ContainerLogsNode{
|
||||
nStat: *s,
|
||||
nParent: p,
|
||||
fidContent: make(map[uint64]io.ReadCloser),
|
||||
cli: cliNode,
|
||||
containerNode: containerNode,
|
||||
}
|
||||
}
|
||||
|
||||
func (cn *ClientNode) MapRunningContainers(t *Tree) []fs.FSNode {
|
||||
ret := make([]fs.FSNode, 0)
|
||||
|
||||
containers, err := cn.ContainerList(cn.ctx, containertypes.ListOptions{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for _, c := range containers {
|
||||
//cl := &ContainerLogsNode{cli: cn}
|
||||
containerNode := ContainerNode(c)
|
||||
api_ng := func(t *Tree) []fs.FSNode {
|
||||
return []fs.FSNode{
|
||||
NewContainerLogsNode(
|
||||
t.NodeNS("Logs", t.Stat().Uid, t.Stat().Gid, 0777), t,
|
||||
cn, containerNode,
|
||||
),
|
||||
}
|
||||
}
|
||||
ctree := NewTree(
|
||||
t.NodeNS(c.ID, t.Stat().Uid, t.Stat().Gid, 0777),
|
||||
t, t.NodeNS,
|
||||
ConcatMapFS(
|
||||
//ContainerNode(c),
|
||||
containerNode,
|
||||
NodeGenerator(api_ng),
|
||||
),
|
||||
)
|
||||
|
||||
ret = append(ret, ctree)
|
||||
}
|
||||
return ret
|
||||
|
||||
}
|
||||
|
||||
func (cn *ClientNode) MapFS(t *Tree) []fs.FSNode {
|
||||
ret := make([]fs.FSNode, 0)
|
||||
|
||||
running_ng := NodeGenerator(cn.MapRunningContainers)
|
||||
|
||||
ret = append(ret, NewTree(
|
||||
t.NodeNS("running", t.Stat().Uid, t.Stat().Gid, 0777),
|
||||
t, t.NodeNS, running_ng,
|
||||
))
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func InitFS() *fs.FS {
|
||||
var rfs fs.FS
|
||||
|
||||
ng := func(t Tree) []fs.FSNode {
|
||||
ctx := context.Background()
|
||||
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer cli.Close()
|
||||
|
||||
containers, err := cli.ContainerList(ctx, containertypes.ListOptions{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
clinode := &ClientNode{cli, ctx}
|
||||
|
||||
ret := make([]fs.FSNode, 0)
|
||||
for _, c := range containers {
|
||||
ret = append(ret, NewTree(t.NodeNS(c.ID, "maxine", "maxine", 0777), t, t.NodeNS, ContainerNode(c).ContainerToFS))
|
||||
|
||||
}
|
||||
return ret
|
||||
}
|
||||
u, _ := user.Current()
|
||||
|
||||
s := rfs.NewStat("/", "maxine", "maxine", 0777)
|
||||
s := rfs.NewStat("/", u.Username, u.Username, 0777)
|
||||
|
||||
t := NewTree(s, nil, rfs.NewStat, ng)
|
||||
t := NewTree(s, nil, rfs.NewStat, clinode)
|
||||
|
||||
rfs.Root = t
|
||||
|
||||
|
Reference in New Issue
Block a user