diff options
Diffstat (limited to 'pkg/k9p/session.go')
-rw-r--r-- | pkg/k9p/session.go | 205 |
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 +} |