about summary refs log tree commit diff
path: root/pkg/k9p/session.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/k9p/session.go')
-rw-r--r--pkg/k9p/session.go205
1 files changed, 205 insertions, 0 deletions
diff --git a/pkg/k9p/session.go b/pkg/k9p/session.go
new file mode 100644
index 0000000..471a6bc
--- /dev/null
+++ b/pkg/k9p/session.go
@@ -0,0 +1,205 @@
+package k9p
+
+import (
+	"context"
+	"runtime"
+	"sync"
+
+	"github.com/docker/go-p9p"
+	"go.terinstock.com/k9p/pkg/resources"
+	"k8s.io/client-go/informers"
+	"k8s.io/client-go/kubernetes"
+)
+
+type Session struct {
+	sync.Mutex
+	aname string
+	uname string
+
+	client         kubernetes.Interface
+	sharedInformer informers.SharedInformerFactory
+	refs           map[p9p.Fid]resources.Ref
+}
+
+func New(ctx context.Context, client kubernetes.Interface) *Session {
+	sharedInformer := informers.NewSharedInformerFactory(client, 0)
+
+	sharedInformer.Core().V1().Namespaces().Informer()
+	sharedInformer.Apps().V1().Deployments().Informer()
+
+	go sharedInformer.Start(ctx.Done())
+	runtime.Gosched()
+
+	return &Session{
+		client:         client,
+		sharedInformer: sharedInformer,
+		refs:           make(map[p9p.Fid]resources.Ref),
+	}
+}
+
+func (k *Session) getRef(fid p9p.Fid) (resources.Ref, error) {
+	k.Lock()
+	defer k.Unlock()
+
+	if fid == p9p.NOFID {
+		return nil, p9p.ErrUnknownfid
+	}
+
+	ref, found := k.refs[fid]
+	if !found {
+		return nil, p9p.ErrUnknownfid
+	}
+
+	return ref, nil
+}
+
+func (k *Session) newRef(fid p9p.Fid, resource resources.Ref) (resources.Ref, error) {
+	k.Lock()
+	defer k.Unlock()
+
+	if fid == p9p.NOFID {
+		return nil, p9p.ErrUnknownfid
+	}
+
+	_, ok := k.refs[fid]
+	if ok {
+		return nil, p9p.ErrDupfid
+	}
+
+	ref := resource
+	k.refs[fid] = ref
+	return ref, nil
+}
+
+func (k *Session) Auth(ctx context.Context, afid p9p.Fid, uname string, aname string) (p9p.Qid, error) {
+	return p9p.Qid{}, nil
+}
+
+func (k *Session) Attach(ctx context.Context, fid p9p.Fid, afid p9p.Fid, uname string, aname string) (p9p.Qid, error) {
+	if uname == "" {
+		return p9p.Qid{}, p9p.MessageRerror{Ename: "no user"}
+	}
+
+	if aname == "" {
+		aname = "/"
+	}
+
+	k.uname = uname
+	k.aname = aname
+
+	ref, err := k.newRef(fid, resources.NewDirRef("/", k, map[string]resources.Ref{
+		"namespaces": resources.NewNamespacesRef(k.client, k),
+		"cluster":    resources.NewDirRef("cluster", k, map[string]resources.Ref{}),
+	}))
+	if err != nil {
+		return p9p.Qid{}, err
+	}
+
+	return ref.Info().Qid, nil
+}
+
+func (k *Session) Clunk(ctx context.Context, fid p9p.Fid) error {
+	_, err := k.getRef(fid)
+	if err != nil {
+		return err
+	}
+
+	k.Lock()
+	defer k.Unlock()
+	delete(k.refs, fid)
+
+	return nil
+}
+
+func (k *Session) Remove(ctx context.Context, fid p9p.Fid) error {
+	return p9p.ErrUnknownMsg
+}
+
+func (k *Session) Walk(ctx context.Context, fid p9p.Fid, newfid p9p.Fid, names ...string) ([]p9p.Qid, error) {
+	var qids []p9p.Qid
+
+	ref, err := k.getRef(fid)
+	if err != nil {
+		return qids, err
+	}
+
+	current := ref
+	for _, name := range names {
+		newResource, err := current.Get(name)
+		if err != nil {
+			break
+		}
+
+		qids = append(qids, newResource.Info().Qid)
+		current = newResource
+	}
+
+	if len(qids) != len(names) {
+		return qids, nil
+	}
+
+	_, err = k.newRef(newfid, current)
+	if err != nil {
+		return qids, err
+	}
+
+	return qids, nil
+}
+
+func (k *Session) Read(ctx context.Context, fid p9p.Fid, p []byte, offset int64) (n int, err error) {
+	ref, err := k.getRef(fid)
+	if err != nil {
+		return 0, err
+	}
+
+	return ref.Read(ctx, p, offset)
+}
+
+func (k *Session) Write(ctx context.Context, fid p9p.Fid, p []byte, offset int64) (n int, err error) {
+	return 0, p9p.ErrUnknownMsg
+}
+
+func (k *Session) Open(ctx context.Context, fid p9p.Fid, mode p9p.Flag) (p9p.Qid, uint32, error) {
+	ref, err := k.getRef(fid)
+	if err != nil {
+		return p9p.Qid{}, 0, err
+	}
+
+	return ref.Info().Qid, 0, nil
+}
+
+func (k *Session) Create(ctx context.Context, parent p9p.Fid, name string, perm uint32, mode p9p.Flag) (p9p.Qid, uint32, error) {
+	return p9p.Qid{}, 0, p9p.ErrUnknownMsg
+}
+
+func (k *Session) Stat(ctx context.Context, fid p9p.Fid) (p9p.Dir, error) {
+	ref, err := k.getRef(fid)
+	if err != nil {
+		return p9p.Dir{}, err
+	}
+
+	return ref.Info(), nil
+}
+
+func (k *Session) WStat(ctx context.Context, fid p9p.Fid, dir p9p.Dir) error {
+	return p9p.ErrUnknownMsg
+}
+
+// Version returns the supported version and msize of the session. This
+// can be affected by negotiating or the level of support provided by the
+// session implementation.
+func (k *Session) Version() (msize int, version string) {
+	return p9p.DefaultMSize, p9p.DefaultVersion
+}
+
+func (k *Session) WaitForCacheSync(stopCh <-chan struct{}) {
+	k.sharedInformer.WaitForCacheSync(stopCh)
+}
+
+func (k *Session) GetAuth() (uname, aname string) {
+	return k.uname, k.aname
+}
+
+func (k *Session) Informer() informers.SharedInformerFactory {
+	return k.sharedInformer
+}