458 lines
12 KiB
Go
458 lines
12 KiB
Go
package view
|
|
|
|
// BOZO!!
|
|
// import (
|
|
// "bytes"
|
|
// "context"
|
|
// "errors"
|
|
// "fmt"
|
|
// "strconv"
|
|
// "time"
|
|
|
|
// "github.com/atotto/clipboard"
|
|
// "github.com/derailed/k9s/internal"
|
|
// "github.com/derailed/k9s/internal/config"
|
|
// "github.com/derailed/k9s/internal/k8s"
|
|
// "github.com/derailed/k9s/internal/resource"
|
|
// "github.com/derailed/k9s/internal/ui"
|
|
// "github.com/derailed/k9s/internal/ui/dialog"
|
|
// "github.com/gdamore/tcell"
|
|
// "github.com/rs/zerolog/log"
|
|
// "k8s.io/apimachinery/pkg/labels"
|
|
// "k8s.io/apimachinery/pkg/runtime"
|
|
// "k8s.io/cli-runtime/pkg/printers"
|
|
// )
|
|
|
|
// // Resource represents a generic resource viewer.
|
|
// type Resource struct {
|
|
// *Table
|
|
|
|
// namespaces map[int]string
|
|
// list resource.List
|
|
// path string
|
|
// gvr string
|
|
// envFn EnvFunc
|
|
// currentNS string
|
|
// }
|
|
|
|
// // NewResource returns a new viewer.
|
|
// func NewResource(title, gvr string, list resource.List) ResourceViewer {
|
|
// return &Resource{
|
|
// Table: NewTable(title),
|
|
// list: list,
|
|
// gvr: gvr,
|
|
// }
|
|
// }
|
|
|
|
// // Init watches all running pods in given namespace
|
|
// func (r *Resource) Init(ctx context.Context) error {
|
|
// log.Debug().Msgf(">>> RESOURCE INIT %s", r.list.GetName())
|
|
|
|
// if err := r.Table.Init(ctx); err != nil {
|
|
// return err
|
|
// }
|
|
// r.envFn = r.defaultK9sEnv
|
|
// r.Table.setFilterFn(r.filterResource)
|
|
// r.setNamespace(r.App().Config.ActiveNamespace())
|
|
// r.refresh()
|
|
// row, _ := r.GetSelection()
|
|
// if row == 0 && r.GetRowCount() > 0 {
|
|
// r.Select(1, 0)
|
|
// }
|
|
|
|
// return nil
|
|
// }
|
|
|
|
// func (s *Resource) SetContextFn(ContextFunc) {}
|
|
// func (s *Resource) SetBindKeysFn(BindKeysFunc) {}
|
|
|
|
// // GVR returns a resource descriptor.
|
|
// func (r *Resource) GVR() string {
|
|
// return r.gvr
|
|
// }
|
|
|
|
// // SetPath sets parent selector.
|
|
// func (r *Resource) SetParentPath(p string) {
|
|
// r.path = p
|
|
// }
|
|
|
|
// // GetTable returns the underlying table view.
|
|
// func (r *Resource) GetTable() *Table { return r.Table }
|
|
|
|
// // SetEnvFn sets the function to pull current viewer env vars.
|
|
// func (r *Resource) SetEnvFn(f EnvFunc) {
|
|
// r.envFn = f
|
|
// }
|
|
|
|
// // Start initializes updates.
|
|
// func (r *Resource) Start() {
|
|
// log.Debug().Msgf("RESOURCE START")
|
|
// r.Stop()
|
|
|
|
// log.Debug().Msgf(">>>>>>> START %s", r.list.GetName())
|
|
// r.Table.Start()
|
|
|
|
// var ctx context.Context
|
|
// ctx, r.cancelFn = context.WithCancel(context.Background())
|
|
// go r.update(ctx)
|
|
// }
|
|
|
|
// // Name returns the component name.
|
|
// func (r *Resource) Name() string {
|
|
// return r.list.GetName()
|
|
// }
|
|
|
|
// func (r *Resource) List() resource.List {
|
|
// return r.list
|
|
// }
|
|
|
|
// func (r *Resource) filterResource(sel string) {
|
|
// r.list.SetLabelSelector(sel)
|
|
// r.refresh()
|
|
// }
|
|
|
|
// func (r *Resource) update(ctx context.Context) {
|
|
// for {
|
|
// select {
|
|
// case <-ctx.Done():
|
|
// log.Debug().Msgf("%s updater canceled!", r.list.GetName())
|
|
// return
|
|
// case <-time.After(time.Duration(r.app.Config.K9s.GetRefreshRate()) * time.Second):
|
|
// r.app.QueueUpdateDraw(func() {
|
|
// r.refresh()
|
|
// })
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
// // ----------------------------------------------------------------------------
|
|
// // Actions()...
|
|
|
|
// func (r *Resource) cpCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|
// if !r.RowSelected() {
|
|
// return evt
|
|
// }
|
|
|
|
// _, n := k8s.Namespaced(r.GetSelectedItem())
|
|
// log.Debug().Msgf("Copied selection to clipboard %q", n)
|
|
// r.app.Flash().Info("Current selection copied to clipboard...")
|
|
// if err := clipboard.WriteAll(n); err != nil {
|
|
// r.app.Flash().Err(err)
|
|
// }
|
|
|
|
// return nil
|
|
// }
|
|
|
|
// func (r *Resource) enterCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|
// log.Debug().Msgf("RES ENTER CMD...")
|
|
// // If in command mode run filter otherwise enter function.
|
|
// if r.filterCmd(evt) == nil || !r.RowSelected() {
|
|
// return nil
|
|
// }
|
|
|
|
// f := r.defaultEnter
|
|
// if r.enterFn != nil {
|
|
// log.Debug().Msgf("Found custom enter")
|
|
// f = r.enterFn
|
|
// }
|
|
// f(r.app, r.list.GetNamespace(), r.list.GetName(), r.GetSelectedItem())
|
|
|
|
// return nil
|
|
// }
|
|
|
|
// func (r *Resource) refreshCmd(*tcell.EventKey) *tcell.EventKey {
|
|
// r.app.Flash().Info("Refreshing...")
|
|
// r.refresh()
|
|
// return nil
|
|
// }
|
|
|
|
// func (r *Resource) deleteCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|
// ss := r.GetSelectedItems()
|
|
// if len(ss) == 0 {
|
|
// return evt
|
|
// }
|
|
|
|
// var msg string
|
|
// if len(ss) > 1 {
|
|
// msg = fmt.Sprintf("Delete %d marked %s?", len(ss), r.list.GetName())
|
|
// } else {
|
|
// msg = fmt.Sprintf("Delete %s %s?", r.list.GetName(), ss[0])
|
|
// }
|
|
// dialog.ShowDelete(r.app.Content.Pages, msg, func(cascade, force bool) {
|
|
// r.ShowDeleted()
|
|
// if len(ss) > 1 {
|
|
// r.app.Flash().Infof("Delete %d marked %s", len(ss), r.list.GetName())
|
|
// } else {
|
|
// r.app.Flash().Infof("Delete resource %s %s", r.list.GetName(), ss[0])
|
|
// }
|
|
// for _, s := range ss {
|
|
// if err := r.list.Resource().Delete(s, cascade, force); err != nil {
|
|
// r.app.Flash().Errf("Delete failed with %s", err)
|
|
// } else {
|
|
// r.app.factory.DeleteForwarder(s)
|
|
// }
|
|
// }
|
|
// r.refresh()
|
|
// }, func() {})
|
|
// return nil
|
|
// }
|
|
|
|
// func (r *Resource) defaultEnter(app *App, ns, _, sel string) {
|
|
// if !r.list.Access(resource.DescribeAccess) {
|
|
// return
|
|
// }
|
|
|
|
// yaml, err := r.list.Resource().Describe(r.gvr, sel)
|
|
// if err != nil {
|
|
// r.app.Flash().Errf("Describe command failed: %s", err)
|
|
// return
|
|
// }
|
|
|
|
// details := NewDetails("Describe")
|
|
// details.SetSubject(sel)
|
|
// details.SetTextColor(r.app.Styles.FgColor())
|
|
// details.SetText(colorizeYAML(r.app.Styles.Views().Yaml, yaml))
|
|
// details.ScrollToBeginning()
|
|
// r.app.inject(details)
|
|
// }
|
|
|
|
// func (r *Resource) describeCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|
// if !r.RowSelected() {
|
|
// return evt
|
|
// }
|
|
// r.defaultEnter(r.app, r.list.GetNamespace(), r.list.GetName(), r.GetSelectedItem())
|
|
|
|
// return nil
|
|
// }
|
|
|
|
// func (r *Resource) viewCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|
// if !r.RowSelected() {
|
|
// return evt
|
|
// }
|
|
|
|
// path := r.GetSelectedItem()
|
|
// log.Debug().Msgf("------ NAMESPACES %q vs %q", path, r.list.GetNamespace())
|
|
// o, err := r.app.factory.Get(r.gvr, path, labels.Everything())
|
|
// if err != nil {
|
|
// r.app.Flash().Errf("Unable to get resource %s", err)
|
|
// return nil
|
|
// }
|
|
|
|
// raw, err := marshalObject(o)
|
|
// if err != nil {
|
|
// r.app.Flash().Errf("Unable to marshal resource %s", err)
|
|
// return nil
|
|
// }
|
|
|
|
// details := NewDetails("YAML")
|
|
// details.SetSubject(path)
|
|
// details.SetTextColor(r.app.Styles.FgColor())
|
|
// details.SetText(colorizeYAML(r.app.Styles.Views().Yaml, raw))
|
|
// details.ScrollToBeginning()
|
|
// r.app.inject(details)
|
|
|
|
// return nil
|
|
// }
|
|
|
|
// func marshalObject(o runtime.Object) (string, error) {
|
|
// var (
|
|
// buff bytes.Buffer
|
|
// p printers.YAMLPrinter
|
|
// )
|
|
// err := p.PrintObj(o, &buff)
|
|
// if err != nil {
|
|
// log.Error().Msgf("Marshal Error %v", err)
|
|
// return "", err
|
|
// }
|
|
|
|
// return buff.String(), nil
|
|
// }
|
|
|
|
// func (r *Resource) editCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|
// if !r.RowSelected() {
|
|
// return evt
|
|
// }
|
|
|
|
// r.Stop()
|
|
// defer r.Start()
|
|
// {
|
|
// ns, po := k8s.Namespaced(r.GetSelectedItem())
|
|
// args := make([]string, 0, 10)
|
|
// args = append(args, "edit")
|
|
// args = append(args, r.list.GetName())
|
|
// args = append(args, "-n", ns)
|
|
// args = append(args, "--context", r.app.Config.K9s.CurrentContext)
|
|
// if cfg := r.app.Conn().Config().Flags().KubeConfig; cfg != nil && *cfg != "" {
|
|
// args = append(args, "--kubeconfig", *cfg)
|
|
// }
|
|
// if !runK(true, r.app, append(args, po)...) {
|
|
// r.app.Flash().Err(errors.New("Edit exec failed"))
|
|
// }
|
|
// }
|
|
|
|
// return evt
|
|
// }
|
|
|
|
// func (r *Resource) setNamespace(ns string) {
|
|
// log.Debug().Msgf("!!!!!! SETTING NS %q", ns)
|
|
// if r.list.Namespaced() {
|
|
// r.currentNS = ns
|
|
// r.list.SetNamespace(ns)
|
|
// }
|
|
// }
|
|
|
|
// func (r *Resource) switchNamespaceCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|
// i, _ := strconv.Atoi(string(evt.Rune()))
|
|
// ns := r.namespaces[i]
|
|
// if ns == "" {
|
|
// ns = resource.AllNamespace
|
|
// }
|
|
// if r.currentNS == ns {
|
|
// return nil
|
|
// }
|
|
|
|
// r.app.switchNS(ns)
|
|
// r.setNamespace(ns)
|
|
// r.app.Flash().Infof("Viewing namespace `%s`...", ns)
|
|
// r.refresh()
|
|
// r.UpdateTitle()
|
|
// r.SelectRow(1, true)
|
|
// r.app.CmdBuff().Reset()
|
|
// if err := r.app.Config.SetActiveNamespace(r.currentNS); err != nil {
|
|
// log.Error().Err(err).Msg("Config save NS failed!")
|
|
// }
|
|
// if err := r.app.Config.Save(); err != nil {
|
|
// log.Error().Err(err).Msg("Config save failed!")
|
|
// }
|
|
|
|
// return nil
|
|
// }
|
|
|
|
// func (r *Resource) refresh() {
|
|
// log.Debug().Msgf("----> Refreshing (%q) -- %q -- `%s", r.currentNS, r.list.GetNamespace(), r.list.GetName())
|
|
// if r.list.Namespaced() {
|
|
// r.list.SetNamespace(r.currentNS)
|
|
// }
|
|
|
|
// if r.app.Conn() == nil {
|
|
// log.Error().Msg("No api connection")
|
|
// return
|
|
// }
|
|
|
|
// ctx := context.WithValue(context.Background(), internal.KeyFactory, r.app.factory)
|
|
// ctx = context.WithValue(ctx, internal.KeyPath, r.path)
|
|
// if err := r.list.Reconcile(ctx, r.gvr); err != nil {
|
|
// r.app.Flash().Err(err)
|
|
// }
|
|
|
|
// data := r.list.Data()
|
|
// // BOZO!!
|
|
// // if r.decorateFn != nil {
|
|
// // data = r.decorateFn(data)
|
|
// // }
|
|
// r.refreshActions()
|
|
// r.Update(data)
|
|
// }
|
|
|
|
// func (r *Resource) namespaceActions(aa ui.KeyActions) {
|
|
// if r.app.Conn() == nil || !r.list.Access(resource.NamespaceAccess) {
|
|
// return
|
|
// }
|
|
// r.namespaces = make(map[int]string, config.MaxFavoritesNS)
|
|
// aa[tcell.Key(ui.NumKeys[0])] = ui.NewKeyAction(resource.AllNamespace, r.switchNamespaceCmd, true)
|
|
// r.namespaces[0] = resource.AllNamespace
|
|
// index := 1
|
|
// for _, n := range r.app.Config.FavNamespaces() {
|
|
// if n == resource.AllNamespace {
|
|
// continue
|
|
// }
|
|
// aa[tcell.Key(ui.NumKeys[index])] = ui.NewKeyAction(n, r.switchNamespaceCmd, true)
|
|
// r.namespaces[index] = n
|
|
// index++
|
|
// }
|
|
// }
|
|
|
|
// func (r *Resource) refreshActions() {
|
|
// aa := ui.KeyActions{
|
|
// ui.KeyC: ui.NewKeyAction("Copy", r.cpCmd, false),
|
|
// tcell.KeyEnter: ui.NewKeyAction("Enter", r.enterCmd, false),
|
|
// tcell.KeyCtrlR: ui.NewKeyAction("Refresh", r.refreshCmd, false),
|
|
// }
|
|
// r.namespaceActions(aa)
|
|
|
|
// if r.list.Access(resource.EditAccess) {
|
|
// aa[ui.KeyE] = ui.NewKeyAction("Edit", r.editCmd, true)
|
|
// }
|
|
// if r.list.Access(resource.DeleteAccess) {
|
|
// aa[tcell.KeyCtrlD] = ui.NewKeyAction("Delete", r.deleteCmd, true)
|
|
// }
|
|
// if r.list.Access(resource.ViewAccess) {
|
|
// aa[ui.KeyY] = ui.NewKeyAction("YAML", r.viewCmd, true)
|
|
// }
|
|
// if r.list.Access(resource.DescribeAccess) {
|
|
// aa[ui.KeyD] = ui.NewKeyAction("Describe", r.describeCmd, true)
|
|
// }
|
|
// r.customActions(aa)
|
|
// r.Actions().Set(aa)
|
|
// }
|
|
|
|
// func (r *Resource) customActions(aa ui.KeyActions) {
|
|
// pp := config.NewPlugins()
|
|
// if err := pp.Load(); err != nil {
|
|
// log.Warn().Msgf("No plugin configuration found")
|
|
// return
|
|
// }
|
|
|
|
// for k, plugin := range pp.Plugin {
|
|
// if !in(plugin.Scopes, r.list.GetName()) {
|
|
// continue
|
|
// }
|
|
// key, err := asKey(plugin.ShortCut)
|
|
// if err != nil {
|
|
// log.Error().Err(err).Msg("Unable to map shortcut to a key")
|
|
// continue
|
|
// }
|
|
// _, ok := aa[key]
|
|
// if ok {
|
|
// log.Error().Err(fmt.Errorf("Doh! you are trying to overide an existing command `%s", k)).Msg("Invalid shortcut")
|
|
// continue
|
|
// }
|
|
// aa[key] = ui.NewKeyAction(
|
|
// plugin.Description,
|
|
// r.execCmd(plugin.Command, plugin.Background, plugin.Args...),
|
|
// true)
|
|
// }
|
|
// }
|
|
|
|
// func (r *Resource) execCmd(bin string, bg bool, args ...string) ui.ActionHandler {
|
|
// return func(evt *tcell.EventKey) *tcell.EventKey {
|
|
// if !r.RowSelected() {
|
|
// return evt
|
|
// }
|
|
|
|
// var (
|
|
// env = r.envFn()
|
|
// aa = make([]string, len(args))
|
|
// err error
|
|
// )
|
|
// for i, a := range args {
|
|
// aa[i], err = env.envFor(a)
|
|
// if err != nil {
|
|
// log.Error().Err(err).Msg("Args match failed")
|
|
// return nil
|
|
// }
|
|
// }
|
|
|
|
// if run(true, r.app, bin, bg, aa...) {
|
|
// r.app.Flash().Info("Custom CMD launched!")
|
|
// } else {
|
|
// r.app.Flash().Info("Custom CMD failed!")
|
|
// }
|
|
// return nil
|
|
// }
|
|
// }
|
|
|
|
// func (r *Resource) defaultK9sEnv() K9sEnv {
|
|
// return defaultK9sEnv(r.app, r.GetSelectedItem(), r.GetRow())
|
|
// }
|