checkpoint

mine
derailed 2019-12-29 12:53:16 -07:00
parent 365fc01f17
commit 5c0fc0845b
13 changed files with 112 additions and 81 deletions

View File

@ -3,6 +3,7 @@ package client
import (
"errors"
"fmt"
"sync"
"github.com/rs/zerolog/log"
v1 "k8s.io/api/core/v1"
@ -19,11 +20,15 @@ type Config struct {
currentContext string
rawConfig *clientcmdapi.Config
restConfig *restclient.Config
mutex *sync.RWMutex
}
// NewConfig returns a new k8s config or an error if the flags are invalid.
func NewConfig(f *genericclioptions.ConfigFlags) *Config {
return &Config{flags: f}
return &Config{
flags: f,
mutex: &sync.RWMutex{},
}
}
// Flags returns configuration flags.
@ -231,12 +236,18 @@ func (c *Config) NamespaceNames(nns []v1.Namespace) []string {
// ConfigAccess return the current kubeconfig api server access configuration.
func (c *Config) ConfigAccess() (clientcmd.ConfigAccess, error) {
c.mutex.RLock()
defer c.mutex.RUnlock()
c.ensureConfig()
return c.clientConfig.ConfigAccess(), nil
}
// RawConfig fetch the current kubeconfig with no overrides.
func (c *Config) RawConfig() (clientcmdapi.Config, error) {
c.mutex.Lock()
defer c.mutex.Unlock()
if c.rawConfig != nil {
if c.rawConfig.CurrentContext == c.currentContext {
return *c.rawConfig, nil

View File

@ -22,7 +22,7 @@ type TableListener interface {
type Table struct {
gvr string
namespace string
data render.TableData
data *render.TableData
listeners []TableListener
inUpdate int32
refreshRate time.Duration
@ -32,7 +32,7 @@ type Table struct {
func NewTable(gvr string) *Table {
return &Table{
gvr: gvr,
data: render.TableData{},
data: render.NewTableData(),
refreshRate: 2 * time.Second,
}
}
@ -81,7 +81,7 @@ func (t *Table) Empty() bool {
// Peek returns model data.
func (t *Table) Peek() render.TableData {
return t.data
return *t.data
}
func (t *Table) updater(ctx context.Context) {
@ -107,13 +107,13 @@ func (t *Table) refresh(ctx context.Context) {
log.Error().Err(err).Msg("Reconcile failed")
t.fireTableLoadFailed(err)
}
t.fireTableChanged(t.data)
t.fireTableChanged(*t.data)
}
// AddListener adds a new model listener.
func (t *Table) AddListener(l TableListener) {
t.listeners = append(t.listeners, l)
t.fireTableChanged(t.data)
t.fireTableChanged(*t.data)
}
// RemoveListener delete a listener from the list.
@ -144,6 +144,9 @@ func (t *Table) fireTableLoadFailed(err error) {
}
func (t *Table) reconcile(ctx context.Context) error {
t.data.Mutex.Lock()
defer t.data.Mutex.Unlock()
log.Debug().Msgf("GOROUTINE %d", runtime.NumGoroutine())
factory, ok := ctx.Value(internal.KeyFactory).(Factory)

View File

@ -1,10 +1,18 @@
package render
import "sync"
// TableData tracks a K8s resource for tabular display.
type TableData struct {
Header HeaderRow
RowEvents RowEvents
Namespace string
Mutex *sync.RWMutex
}
// NewTableData returns a new table.
func NewTableData() *TableData {
return &TableData{Mutex: &sync.RWMutex{}}
}
// Clear clears out the entire table.

View File

@ -134,6 +134,9 @@ func (t *Table) SetSortCol(index, count int, asc bool) {
// Update table content.
func (t *Table) Update(data render.TableData) {
data.Mutex.RLock()
defer data.Mutex.RUnlock()
var firstRow bool
if t.GetRowCount() == 0 {
firstRow = true

View File

@ -69,14 +69,14 @@ func (t *testModel) InNamespace(string) bool { return true }
func (t *testModel) SetRefreshRate(time.Duration) {}
func makeTableData() render.TableData {
return render.TableData{
Namespace: "",
Header: render.HeaderRow{
t := render.NewTableData()
t.Namespace = ""
t.Header = render.HeaderRow{
render.Header{Name: "a"},
render.Header{Name: "b"},
render.Header{Name: "c"},
},
RowEvents: render.RowEvents{
}
t.RowEvents = render.RowEvents{
render.RowEvent{
Row: render.Row{
ID: "r1",
@ -89,6 +89,7 @@ func makeTableData() render.TableData {
Fields: render.Fields{"blee", "duh", "zorg"},
},
},
},
}
return *t
}

View File

@ -193,7 +193,9 @@ func (a *App) Resume() {
var ctx context.Context
ctx, a.cancelFn = context.WithCancel(context.Background())
go a.clusterUpdater(ctx)
a.StylesUpdater(ctx, a)
if err := a.StylesUpdater(ctx, a); err != nil {
log.Error().Err(err).Msgf("Styles update failed")
}
}
func (a *App) clusterUpdater(ctx context.Context) {

View File

@ -1,6 +1,8 @@
package view
import (
"strings"
"github.com/derailed/k9s/internal/client"
"github.com/derailed/k9s/internal/render"
"github.com/derailed/k9s/internal/ui"
@ -52,7 +54,7 @@ func (d *Deploy) showPods(app *App, _, _, path string) {
app.Flash().Err(err)
}
showPodsFromSelector(app, path, dp.Spec.Selector)
showPodsFromSelector(app, strings.Replace(path, "/", "::", 1), dp.Spec.Selector)
}
// Helpers...

View File

@ -1,6 +1,8 @@
package view
import (
"strings"
"github.com/derailed/k9s/internal/client"
"github.com/derailed/k9s/internal/render"
"github.com/derailed/k9s/internal/ui"
@ -47,5 +49,5 @@ func (d *DaemonSet) showPods(app *App, _, _, path string) {
d.App().Flash().Err(err)
}
showPodsFromSelector(app, path, ds.Spec.Selector)
showPodsFromSelector(app, strings.Replace(path, "/", "::", 1), ds.Spec.Selector)
}

View File

@ -41,7 +41,6 @@ type Log struct {
cancelFn context.CancelFunc
previous bool
gvr client.GVR
fullScreen bool
}
var _ model.Component = &Log{}

View File

@ -39,7 +39,7 @@ func (l *LogsExtender) logsCmd(prev bool) func(evt *tcell.EventKey) *tcell.Event
if path == "" {
return nil
}
if l.GetTable().Path != "" {
if isResourcePath(l.GetTable().Path) {
path = l.GetTable().Path
}
l.showLogs(path, prev)
@ -48,11 +48,15 @@ func (l *LogsExtender) logsCmd(prev bool) func(evt *tcell.EventKey) *tcell.Event
}
}
func isResourcePath(p string) bool {
ns, n := client.Namespaced(p)
return ns != "" && n != ""
}
func (l *LogsExtender) showLogs(path string, prev bool) {
log.Debug().Msgf("SHOWING LOGS path %q", path)
co := ""
if l.containerFn != nil {
log.Debug().Msgf("CUSTOM CO FUNC")
co = l.containerFn()
}
if err := l.App().inject(NewLog(client.GVR(l.GVR()), path, co, prev)); err != nil {

View File

@ -1,6 +1,8 @@
package view
import (
"strings"
"github.com/derailed/k9s/internal/client"
"github.com/derailed/k9s/internal/render"
"github.com/derailed/k9s/internal/ui"
@ -51,5 +53,5 @@ func (s *StatefulSet) showPods(app *App, _, gvr, path string) {
app.Flash().Err(err)
}
showPodsFromSelector(app, path, sts.Spec.Selector)
showPodsFromSelector(app, strings.Replace(path, "/", "::", 1), sts.Spec.Selector)
}

View File

@ -33,14 +33,14 @@ func TestTableNew(t *testing.T) {
v := NewTable("test")
v.Init(makeContext())
data := render.TableData{
Header: render.HeaderRow{
data := render.NewTableData()
data.Header = render.HeaderRow{
render.Header{Name: "NAMESPACE"},
render.Header{Name: "NAME", Align: tview.AlignRight},
render.Header{Name: "FRED"},
render.Header{Name: "AGE", Decorator: render.AgeDecorator},
},
RowEvents: render.RowEvents{
}
data.RowEvents = render.RowEvents{
render.RowEvent{
Row: render.Row{
Fields: render.Fields{"ns1", "a", "10", "3m"},
@ -51,10 +51,10 @@ func TestTableNew(t *testing.T) {
Fields: render.Fields{"ns1", "b", "15", "1m"},
},
},
},
Namespace: "",
}
v.Update(data)
data.Namespace = ""
v.Update(*data)
assert.Equal(t, 3, v.GetRowCount())
}
@ -101,14 +101,15 @@ func (t *testTableModel) InNamespace(string) bool { return true }
func (t *testTableModel) SetRefreshRate(time.Duration) {}
func makeTableData() render.TableData {
return render.TableData{
Header: render.HeaderRow{
t := render.NewTableData()
t.Header = render.HeaderRow{
render.Header{Name: "NAMESPACE"},
render.Header{Name: "NAME", Align: tview.AlignRight},
render.Header{Name: "FRED"},
render.Header{Name: "AGE", Decorator: render.AgeDecorator},
},
RowEvents: render.RowEvents{
}
t.RowEvents = render.RowEvents{
render.RowEvent{
Row: render.Row{
Fields: render.Fields{"ns1", "blee", "10", "3m"},
@ -120,9 +121,10 @@ func makeTableData() render.TableData {
},
Deltas: render.DeltaRow{"", "", "20", ""},
},
},
Namespace: "",
}
t.Namespace = ""
return *t
}
func makeContext() context.Context {

View File

@ -8,9 +8,6 @@ import (
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
_ "k8s.io/client-go/plugin/pkg/client/auth"
"net/http"
_ "net/http/pprof"
)
func init() {
@ -23,11 +20,6 @@ func main() {
if err != nil {
panic(err)
}
go func() {
http.ListenAndServe("localhost:6060", nil)
}()
log.Logger = log.Output(zerolog.ConsoleWriter{Out: file})
cmd.Execute()