ckeckpoint

mine
derailed 2019-11-13 07:37:23 -07:00
parent 7a89c4c1e4
commit 05558c89fa
14 changed files with 135 additions and 115 deletions

View File

@ -44,7 +44,7 @@ type Bench struct {
func NewBench(title, gvr string, _ resource.List) ResourceViewer {
return &Bench{
MasterDetail: NewMasterDetail(),
MasterDetail: NewMasterDetail(title),
}
}

View File

@ -1,7 +1,6 @@
package view
import (
"context"
"errors"
"fmt"
"strings"
@ -35,11 +34,6 @@ func NewContainer(title string, list resource.List, path string) ResourceViewer
return &c
}
// Init initializes a container view.
func (c *Container) Init(ctx context.Context) {
c.Resource.Init(ctx)
}
// Start starts the component.
func (c *Container) Start() {}

View File

@ -35,9 +35,9 @@ type ScreenDump struct {
app *App
}
func NewScreenDump(_, _ string, _ resource.List) ResourceViewer {
func NewScreenDump(title, _ string, _ resource.List) ResourceViewer {
return &ScreenDump{
MasterDetail: NewMasterDetail(),
MasterDetail: NewMasterDetail(title),
}
}

View File

@ -1,6 +1,8 @@
package view
import (
"context"
"github.com/derailed/k9s/internal/resource"
"github.com/derailed/k9s/internal/ui"
"github.com/gdamore/tcell"
@ -14,17 +16,23 @@ type LogResource struct {
*Resource
containerFn containerFn
logs *Logs
}
func NewLogResource(title, gvr string, list resource.List) *LogResource {
l := LogResource{
Resource: NewResource(title, gvr, list),
}
l.AddPage("logs", NewLogs(list.GetName(), &l), true, false)
l.logs = NewLogs(list.GetName(), &l)
return &l
}
func (l *LogResource) Init(ctx context.Context) {
l.Resource.Init(ctx)
l.logs.Init(ctx)
}
func (l *LogResource) extraActions(aa ui.KeyActions) {
aa[ui.KeyL] = ui.NewKeyAction("Logs", l.logsCmd, true)
aa[ui.KeyShiftL] = ui.NewKeyAction("Logs Previous", l.prevLogsCmd, true)
@ -68,13 +76,12 @@ func (l *LogResource) showLogs(prev bool) {
return
}
logs := l.GetPrimitive("logs").(*Logs)
co := ""
if l.containerFn != nil {
co = l.containerFn()
}
logs.reload(co, l, prev)
l.switchPage("logs")
l.logs.reload(co, l, prev)
l.Push(l.logs)
}
func (l *LogResource) backCmd(evt *tcell.EventKey) *tcell.EventKey {

View File

@ -8,7 +8,6 @@ import (
"github.com/derailed/k9s/internal/model"
"github.com/derailed/k9s/internal/resource"
"github.com/derailed/k9s/internal/ui"
"github.com/derailed/tview"
"github.com/gdamore/tcell"
"github.com/rs/zerolog/log"
)
@ -29,7 +28,7 @@ type (
// Logs presents a collection of logs.
Logs struct {
*tview.Pages
*ui.Pages
app *App
parent loggable
@ -41,11 +40,19 @@ type (
// NewLogs returns a new logs viewer.
func NewLogs(title string, parent loggable) *Logs {
return &Logs{
Pages: tview.NewPages(),
Pages: ui.NewPages(),
parent: parent,
}
}
func (l *Logs) Init(ctx context.Context) {
l.app = ctx.Value(ui.KeyApp).(*App)
}
func (l *Logs) Start() {}
func (l *Logs) Stop() {}
func (l *Logs) Name() string { return "logs" }
// Protocol...
func (l *Logs) reload(co string, parent loggable, prevLogs bool) {
@ -171,7 +178,7 @@ func updateLogs(ctx context.Context, c <-chan string, l *Log, buffSize int) {
func (l *Logs) backCmd(evt *tcell.EventKey) *tcell.EventKey {
l.stop()
l.parent.switchPage("master")
l.parent.Pop()
return evt
}

View File

@ -13,12 +13,15 @@ type MasterDetail struct {
enterFn enterFn
extraActionsFn func(ui.KeyActions)
details *Details
currentNS string
title string
}
// NewMasterDetail returns a new master-detail viewer.
func NewMasterDetail() *MasterDetail {
func NewMasterDetail(title string) *MasterDetail {
return &MasterDetail{
PageStack: NewPageStack(),
title: title,
}
}
@ -26,7 +29,7 @@ func NewMasterDetail() *MasterDetail {
func (m *MasterDetail) Init(ctx context.Context) {
m.PageStack.Init(ctx)
t := NewTable("master")
t := NewTable(m.title)
t.Init(ctx)
m.Push(t)
@ -49,7 +52,7 @@ func (m *MasterDetail) showMaster() {
}
func (m *MasterDetail) masterPage() *Table {
return m.GetPrimitive("table").(*Table)
return m.GetPrimitive(m.title).(*Table)
}
func (m *MasterDetail) showDetails() {

View File

@ -3,6 +3,7 @@ package view
import (
"fmt"
"github.com/derailed/k9s/internal/model"
"github.com/derailed/k9s/internal/resource"
"github.com/derailed/k9s/internal/ui"
"github.com/derailed/k9s/internal/watch"
@ -20,12 +21,15 @@ const (
type loggable interface {
getSelection() string
getList() resource.List
switchPage(n string)
Pop() (model.Component, bool)
}
// Pod represents a pod viewer.
type Pod struct {
*Resource
logs *Logs
picker *selectList
}
// NewPod returns a new viewer.
@ -36,14 +40,12 @@ func NewPod(title, gvr string, list resource.List) ResourceViewer {
p.extraActionsFn = p.extraActions
p.enterFn = p.listContainers
picker := newSelectList(&p)
{
picker.setActions(ui.KeyActions{
tcell.KeyEscape: {Description: "Back", Action: p.backCmd, Visible: true},
})
}
p.AddPage("picker", picker, true, false)
p.AddPage("logs", NewLogs(list.GetName(), &p), true, false)
p.picker = newSelectList(&p)
p.picker.setActions(ui.KeyActions{
tcell.KeyEscape: {Description: "Back", Action: p.backCmd, Visible: true},
})
p.logs = NewLogs(list.GetName(), &p)
return &p
}
@ -144,7 +146,7 @@ func (p *Pod) viewLogs(prev bool) bool {
func (p *Pod) showLogs(path, co string, parent loggable, prev bool) {
l := p.GetPrimitive("logs").(*Logs)
l.reload(co, parent, prev)
p.switchPage("logs")
p.Push(p.logs)
}
func (p *Pod) shellCmd(evt *tcell.EventKey) *tcell.EventKey {
@ -167,7 +169,7 @@ func (p *Pod) shellCmd(evt *tcell.EventKey) *tcell.EventKey {
picker.SetSelectedFunc(func(i int, t, d string, r rune) {
p.shellIn(sel, t)
})
p.switchPage("picker")
p.Push(p.picker)
return evt
}

View File

@ -32,13 +32,12 @@ type Resource struct {
decorateFn decorateFn
envFn envFn
gvr string
currentNS string
}
// NewResource returns a new viewer.
func NewResource(title, gvr string, list resource.List) *Resource {
return &Resource{
MasterDetail: NewMasterDetail(),
MasterDetail: NewMasterDetail(title),
list: list,
gvr: gvr,
}
@ -127,11 +126,12 @@ func (r *Resource) update(ctx context.Context) {
}
func (r *Resource) backCmd(*tcell.EventKey) *tcell.EventKey {
r.switchPage("master")
r.Pop()
return nil
}
func (r *Resource) switchPage(p string) {
func (r *Resource) switchPage1(p string) {
log.Debug().Msgf("Switching page to %s", p)
if _, ok := r.CurrentPage().Item.(*Table); ok {
r.Stop()
@ -211,7 +211,7 @@ func (r *Resource) deleteCmd(evt *tcell.EventKey) *tcell.EventKey {
}
r.refresh()
}, func() {
r.switchPage("master")
r.Pop()
})
return nil
}
@ -254,7 +254,7 @@ func (r *Resource) defaultEnter(app *App, ns, _, selection string) {
details.SetTextColor(r.app.Styles.FgColor())
details.SetText(colorizeYAML(r.app.Styles.Views().Yaml, yaml))
details.ScrollToBeginning()
r.switchPage("details")
r.showDetails()
}
func (r *Resource) describeCmd(evt *tcell.EventKey) *tcell.EventKey {

View File

@ -97,8 +97,7 @@ func (r *ReplicaSet) rollbackCmd(evt *tcell.EventKey) *tcell.EventKey {
}
func (r *ReplicaSet) dismissModal() {
r.RemovePage("confirm")
r.switchPage("master")
r.Pop()
}
func (r *ReplicaSet) showModal(msg string, done func(int, string)) {

View File

@ -57,7 +57,7 @@ func (s *Secret) decodeCmd(evt *tcell.EventKey) *tcell.EventKey {
details.SetTextColor(s.app.Styles.FgColor())
details.SetText(colorizeYAML(s.app.Styles.Views().Yaml, string(raw)))
details.ScrollToBeginning()
s.switchPage("details")
s.showDetails()
return nil
}

View File

@ -1,6 +1,8 @@
package view
import (
"context"
"github.com/derailed/k9s/internal/model"
"github.com/derailed/k9s/internal/resource"
"github.com/derailed/k9s/internal/ui"
@ -37,16 +39,21 @@ func newSelectList(parent loggable) *selectList {
return &v
}
func (v *selectList) Init(context.Context) {}
func (v *selectList) Start() {}
func (v *selectList) Stop() {}
func (v *selectList) Name() string { return "picker" }
func (v *selectList) back(evt *tcell.EventKey) *tcell.EventKey {
v.parent.switchPage("master")
v.parent.Pop()
return nil
}
// Protocol...
func (v *selectList) switchPage(p string) {
v.parent.switchPage(p)
func (v *selectList) Pop() {
v.parent.Pop()
}
func (v *selectList) getList() resource.List {

View File

@ -20,6 +20,7 @@ type Service struct {
*Resource
bench *perf.Benchmark
logs *Logs
}
func NewService(title, gvr string, list resource.List) ResourceViewer {
@ -28,31 +29,31 @@ func NewService(title, gvr string, list resource.List) ResourceViewer {
}
s.extraActionsFn = s.extraActions
s.enterFn = s.showPods
s.AddPage("logs", NewLogs(list.GetName(), &s), true, false)
s.logs = NewLogs(list.GetName(), &s)
return &s
}
// Protocol...
func (v *Service) getList() resource.List {
return v.list
func (s *Service) getList() resource.List {
return s.list
}
func (v *Service) getSelection() string {
return v.masterPage().GetSelectedItem()
func (s *Service) getSelection() string {
return s.masterPage().GetSelectedItem()
}
func (v *Service) extraActions(aa ui.KeyActions) {
aa[ui.KeyL] = ui.NewKeyAction("Logs", v.logsCmd, true)
aa[tcell.KeyCtrlB] = ui.NewKeyAction("Bench", v.benchCmd, true)
aa[tcell.KeyCtrlK] = ui.NewKeyAction("Bench Stop", v.benchStopCmd, true)
aa[ui.KeyShiftT] = ui.NewKeyAction("Sort Type", v.sortColCmd(1, false), false)
func (s *Service) extraActions(aa ui.KeyActions) {
aa[ui.KeyL] = ui.NewKeyAction("Logs", s.logsCmd, true)
aa[tcell.KeyCtrlB] = ui.NewKeyAction("Bench", s.benchCmd, true)
aa[tcell.KeyCtrlK] = ui.NewKeyAction("Bench Stop", s.benchStopCmd, true)
aa[ui.KeyShiftT] = ui.NewKeyAction("Sort Type", s.sortColCmd(1, false), false)
}
func (v *Service) sortColCmd(col int, asc bool) func(evt *tcell.EventKey) *tcell.EventKey {
func (s *Service) sortColCmd(col int, asc bool) func(evt *tcell.EventKey) *tcell.EventKey {
return func(evt *tcell.EventKey) *tcell.EventKey {
t := v.masterPage()
t := s.masterPage()
t.SetSortCol(t.NameColIndex()+col, 0, asc)
t.Refresh()
@ -60,63 +61,62 @@ func (v *Service) sortColCmd(col int, asc bool) func(evt *tcell.EventKey) *tcell
}
}
func (v *Service) showPods(app *App, ns, res, sel string) {
s := k8s.NewService(app.Conn())
func (s *Service) showPods(app *App, ns, res, sel string) {
ns, n := namespaced(sel)
svc, err := s.Get(ns, n)
svc, err := k8s.NewService(app.Conn()).Get(ns, n)
if err != nil {
app.Flash().Err(err)
return
}
if s, ok := svc.(*v1.Service); ok {
v.showSvcPods(ns, s.Spec.Selector, v.backCmd)
if sv, ok := svc.(*v1.Service); ok {
s.showSvcPods(ns, sv.Spec.Selector, s.backCmd)
}
}
func (v *Service) logsCmd(evt *tcell.EventKey) *tcell.EventKey {
if !v.masterPage().RowSelected() {
func (s *Service) logsCmd(evt *tcell.EventKey) *tcell.EventKey {
if !s.masterPage().RowSelected() {
return evt
}
l := v.GetPrimitive("logs").(*Logs)
l.reload("", v, false)
v.switchPage("logs")
l := s.GetPrimitive("logs").(*Logs)
l.reload("", s, false)
s.Push(s.logs)
return nil
}
func (v *Service) backCmd(evt *tcell.EventKey) *tcell.EventKey {
func (s *Service) backCmd(evt *tcell.EventKey) *tcell.EventKey {
// Reset namespace to what it was
if err := v.app.Config.SetActiveNamespace(v.list.GetNamespace()); err != nil {
if err := s.app.Config.SetActiveNamespace(s.list.GetNamespace()); err != nil {
log.Error().Err(err).Msg("Unable to set active namespace")
}
v.app.inject(v)
s.app.inject(s)
return nil
}
func (v *Service) benchStopCmd(evt *tcell.EventKey) *tcell.EventKey {
if v.bench != nil {
func (s *Service) benchStopCmd(evt *tcell.EventKey) *tcell.EventKey {
if s.bench != nil {
log.Debug().Msg(">>> Benchmark canceled!!")
v.app.status(ui.FlashErr, "Benchmark Canceled!")
v.bench.Cancel()
s.app.status(ui.FlashErr, "Benchmark Canceled!")
s.bench.Cancel()
}
v.app.StatusReset()
s.app.StatusReset()
return nil
}
func (v *Service) checkSvc(row int) error {
svcType := trimCellRelative(v.masterPage(), row, 1)
func (s *Service) checkSvc(row int) error {
svcType := trimCellRelative(s.masterPage(), row, 1)
if svcType != "NodePort" && svcType != "LoadBalancer" {
return errors.New("You must select a reachable service")
}
return nil
}
func (v *Service) getExternalPort(row int) (string, error) {
ports := trimCellRelative(v.masterPage(), row, 5)
func (s *Service) getExternalPort(row int) (string, error) {
ports := trimCellRelative(s.masterPage(), row, 5)
pp := strings.Split(ports, " ")
if len(pp) == 0 {
@ -132,75 +132,75 @@ func (v *Service) getExternalPort(row int) (string, error) {
return tokens[1], nil
}
func (v *Service) reloadBenchCfg() error {
func (s *Service) reloadBenchCfg() error {
// BOZO!! Poorman Reload bench to make sure we pick up updates if any.
path := ui.BenchConfig(v.app.Config.K9s.CurrentCluster)
return v.app.Bench.Reload(path)
path := ui.BenchConfig(s.app.Config.K9s.CurrentCluster)
return s.app.Bench.Reload(path)
}
func (v *Service) benchCmd(evt *tcell.EventKey) *tcell.EventKey {
if !v.masterPage().RowSelected() || v.bench != nil {
func (s *Service) benchCmd(evt *tcell.EventKey) *tcell.EventKey {
if !s.masterPage().RowSelected() || s.bench != nil {
return evt
}
if err := v.reloadBenchCfg(); err != nil {
v.app.Flash().Err(err)
if err := s.reloadBenchCfg(); err != nil {
s.app.Flash().Err(err)
return nil
}
sel := v.getSelection()
cfg, ok := v.app.Bench.Benchmarks.Services[sel]
sel := s.getSelection()
cfg, ok := s.app.Bench.Benchmarks.Services[sel]
if !ok {
v.app.Flash().Errf("No bench config found for service %s", sel)
s.app.Flash().Errf("No bench config found for service %s", sel)
return nil
}
cfg.Name = sel
log.Debug().Msgf("Benchmark config %#v", cfg)
row, _ := v.masterPage().GetSelection()
if err := v.checkSvc(row); err != nil {
v.app.Flash().Err(err)
row, _ := s.masterPage().GetSelection()
if err := s.checkSvc(row); err != nil {
s.app.Flash().Err(err)
return nil
}
port, err := v.getExternalPort(row)
port, err := s.getExternalPort(row)
if err != nil {
v.app.Flash().Err(err)
s.app.Flash().Err(err)
return nil
}
if err := v.runBenchmark(port, cfg); err != nil {
v.app.Flash().Errf("Benchmark failed %v", err)
v.app.StatusReset()
v.bench = nil
if err := s.runBenchmark(port, cfg); err != nil {
s.app.Flash().Errf("Benchmark failed %v", err)
s.app.StatusReset()
s.bench = nil
}
return nil
}
func (v *Service) runBenchmark(port string, cfg config.BenchConfig) error {
func (s *Service) runBenchmark(port string, cfg config.BenchConfig) error {
var err error
base := "http://" + cfg.HTTP.Host + ":" + port + cfg.HTTP.Path
if v.bench, err = perf.NewBenchmark(base, cfg); err != nil {
if s.bench, err = perf.NewBenchmark(base, cfg); err != nil {
return err
}
v.app.status(ui.FlashWarn, "Benchmark in progress...")
s.app.status(ui.FlashWarn, "Benchmark in progress...")
log.Debug().Msg("Bench starting...")
go v.bench.Run(v.app.Config.K9s.CurrentCluster, v.benchDone)
go s.bench.Run(s.app.Config.K9s.CurrentCluster, s.benchDone)
return nil
}
func (v *Service) benchDone() {
func (s *Service) benchDone() {
log.Debug().Msg("Bench Completed!")
v.app.QueueUpdate(func() {
if v.bench.Canceled() {
v.app.status(ui.FlashInfo, "Benchmark canceled")
s.app.QueueUpdate(func() {
if s.bench.Canceled() {
s.app.status(ui.FlashInfo, "Benchmark canceled")
} else {
v.app.status(ui.FlashInfo, "Benchmark Completed!")
v.bench.Cancel()
s.app.status(ui.FlashInfo, "Benchmark Completed!")
s.bench.Cancel()
}
v.bench = nil
go benchTimedOut(v.app)
s.bench = nil
go benchTimedOut(s.app)
})
}
@ -211,10 +211,10 @@ func benchTimedOut(app *App) {
})
}
func (v *Service) showSvcPods(ns string, sel map[string]string, a ui.ActionHandler) {
var s []string
func (s *Service) showSvcPods(ns string, sel map[string]string, a ui.ActionHandler) {
var labels []string
for k, v := range sel {
s = append(s, fmt.Sprintf("%s=%s", k, v))
labels = append(labels, fmt.Sprintf("%s=%s", k, v))
}
showPods(v.app, ns, strings.Join(s, ","), "", a)
showPods(s.app, ns, strings.Join(labels, ","), "", a)
}

View File

@ -33,7 +33,7 @@ func (t *Table) Init(ctx context.Context) {
func (t *Table) Start() {}
func (t *Table) Stop() {}
func (t *Table) Name() string { return "table" }
func (t *Table) Name() string { return t.GetBaseTitle() }
// BufferChanged indicates the buffer was changed.
func (t *Table) BufferChanged(s string) {}

View File

@ -118,7 +118,7 @@ func (i *Informer) init(ns string) {
// List items from store.
func (i *Informer) List(res, ns string, opts metav1.ListOptions) (k8s.Collection, error) {
if i == nil {
return nil, errors.New("Invalid informer")
return nil, errors.New("Invalid List informer")
}
if i, ok := i.informers[res]; ok {
@ -131,7 +131,8 @@ func (i *Informer) List(res, ns string, opts metav1.ListOptions) (k8s.Collection
// Get a resource by name.
func (i *Informer) Get(res, fqn string, opts metav1.GetOptions) (interface{}, error) {
if i == nil {
return nil, errors.New("Invalid informer")
panic("blee")
return nil, errors.New("Invalid Get informer")
}
if informer, ok := i.informers[res]; ok {