From d6d5f3267200452593b06258b65d086d5ebb3934 Mon Sep 17 00:00:00 2001 From: derailed Date: Fri, 21 Jun 2019 22:08:53 -0600 Subject: [PATCH] refactor list --- internal/resource/helpers.go | 18 ++-- internal/resource/list.go | 161 +++++++++++++++++------------------ internal/views/app.go | 2 +- 3 files changed, 90 insertions(+), 91 deletions(-) diff --git a/internal/resource/helpers.go b/internal/resource/helpers.go index 243048a0..0d3d5e56 100644 --- a/internal/resource/helpers.go +++ b/internal/resource/helpers.go @@ -35,13 +35,12 @@ const ( NAValue = "n/a" ) -func toSelector(m map[string]string) string { - s := make([]string, 0, len(m)) - for k, v := range m { - s = append(s, k+"="+v) +func metaFQN(m metav1.ObjectMeta) string { + if m.Namespace == "" { + return m.Name } - return strings.Join(s, ",") + return fqn(m.Namespace, m.Name) } func fqn(ns, n string) string { @@ -51,6 +50,15 @@ func fqn(ns, n string) string { return ns + "/" + n } +func toSelector(m map[string]string) string { + s := make([]string, 0, len(m)) + for k, v := range m { + s = append(s, k+"="+v) + } + + return strings.Join(s, ",") +} + func empty(s []string) bool { for _, v := range s { if len(v) != 0 { diff --git a/internal/resource/list.go b/internal/resource/list.go index 79961849..7ff52b6e 100644 --- a/internal/resource/list.go +++ b/internal/resource/list.go @@ -5,7 +5,6 @@ import ( "reflect" wa "github.com/derailed/k9s/internal/watch" - "github.com/rs/zerolog/log" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/watch" @@ -227,15 +226,7 @@ func (l *list) Data() TableData { } } -func metaFQN(m metav1.ObjectMeta) string { - if m.Namespace == "" { - return m.Name - } - - return fqn(m.Namespace, m.Name) -} - -func (l *list) fetchFromStore(informer *wa.Informer, ns string) (Columnars, error) { +func (l *list) load(informer *wa.Informer, ns string) (Columnars, error) { rr, err := informer.List(l.name, ns, metav1.ListOptions{ FieldSelector: l.resource.GetFieldSelector(), LabelSelector: l.resource.GetLabelSelector(), @@ -245,45 +236,10 @@ func (l *list) fetchFromStore(informer *wa.Informer, ns string) (Columnars, erro } items := make(Columnars, 0, len(rr)) - opts := metav1.GetOptions{} for _, r := range rr { - var ( - fqn string - res Columnar - ) - switch o := r.(type) { - case *v1.Node: - fqn = metaFQN(o.ObjectMeta) - res = l.resource.New(r) - nmx, err := informer.Get(wa.NodeMXIndex, fqn, opts) - if err != nil { - log.Warn().Err(err).Msg("NodeMetrics") - } - if mx, ok := nmx.(*mv1beta1.NodeMetrics); ok { - res.SetNodeMetrics(mx) - } - case *v1.Pod: - fqn = metaFQN(o.ObjectMeta) - res = l.resource.New(r) - pmx, err := informer.Get(wa.PodMXIndex, fqn, opts) - if err != nil { - log.Warn().Err(err).Msgf("PodMetrics %s", fqn) - } - if mx, ok := pmx.(*mv1beta1.PodMetrics); ok { - res.SetPodMetrics(mx) - } - case v1.Container: - fqn = ns - res = l.resource.New(r) - pmx, err := informer.Get(wa.PodMXIndex, fqn, opts) - if err != nil { - log.Warn().Err(err).Msgf("PodMetrics %s", fqn) - } - if mx, ok := pmx.(*mv1beta1.PodMetrics); ok { - res.SetPodMetrics(mx) - } - default: - return items, fmt.Errorf("No informer matched %s:%s", l.name, ns) + res, err := l.fetchResource(informer, r, ns) + if err != nil { + return nil, err } items = append(items, res) } @@ -291,6 +247,35 @@ func (l *list) fetchFromStore(informer *wa.Informer, ns string) (Columnars, erro return items, nil } +func (l *list) fetchResource(informer *wa.Informer, r interface{}, ns string) (Columnar, error) { + var err error + + res := l.resource.New(r) + switch o := r.(type) { + case *v1.Node: + fqn := metaFQN(o.ObjectMeta) + nmx, err := informer.Get(wa.NodeMXIndex, fqn, metav1.GetOptions{}) + if err == nil { + res.SetNodeMetrics(nmx.(*mv1beta1.NodeMetrics)) + } + case *v1.Pod: + fqn := metaFQN(o.ObjectMeta) + pmx, err := informer.Get(wa.PodMXIndex, fqn, metav1.GetOptions{}) + if err == nil { + res.SetPodMetrics(pmx.(*mv1beta1.PodMetrics)) + } + case v1.Container: + pmx, err := informer.Get(wa.PodMXIndex, ns, metav1.GetOptions{}) + if err == nil { + res.SetPodMetrics(pmx.(*mv1beta1.PodMetrics)) + } + default: + err = fmt.Errorf("No informer matched %s:%s", l.name, ns) + } + + return res, err +} + // Reconcile previous vs current state and emits delta events. func (l *list) Reconcile(informer *wa.Informer, path *string) error { ns := l.namespace @@ -298,41 +283,63 @@ func (l *list) Reconcile(informer *wa.Informer, path *string) error { ns = *path } - var ( - items Columnars - err error - ) - items, err = l.fetchFromStore(informer, ns) - if err != nil { - if items, err = l.resource.List(l.namespace); err != nil { - return err - } - } - - if len(l.cache) == 0 { - for _, i := range items { - ff := i.Fields(l.namespace) - l.cache[i.Name()] = newRowEvent(New, ff, make(Row, len(ff))) - } + items, err := l.load(informer, ns) + if err == nil { + l.update(items) return nil } + if items, err = l.resource.List(l.namespace); err != nil { + return err + } + l.update(items) + + return nil +} + +func (l *list) update(items Columnars) { + first := len(l.cache) == 0 kk := make([]string, 0, len(items)) for _, i := range items { - a := watch.Added - ff := i.Fields(l.namespace) - dd := make(Row, len(ff)) kk = append(kk, i.Name()) + ff := i.Fields(l.namespace) + if first { + l.cache[i.Name()] = newRowEvent(New, ff, make(Row, len(ff))) + continue + } + dd := make(Row, len(ff)) + a := watch.Added if evt, ok := l.cache[i.Name()]; ok { a = computeDeltas(evt, ff[:len(ff)-1], dd) } l.cache[i.Name()] = newRowEvent(a, ff, dd) } - l.ensureDeletes(kk) - return nil + if first { + return + } + l.ensureDeletes(kk) } +// EnsureDeletes delete items in cache that are no longer valid. +func (l *list) ensureDeletes(kk []string) { + for k := range l.cache { + var found bool + for i, key := range kk { + if k == key { + found = true + kk = append(kk[:i], kk[i+1:]...) + break + } + } + if !found { + delete(l.cache, k) + } + } +} + +// Helpers... + func computeDeltas(evt *RowEvent, newRow, deltas Row) watch.EventType { oldRow := evt.Fields[:len(evt.Fields)-1] a := Unchanged @@ -346,19 +353,3 @@ func computeDeltas(evt *RowEvent, newRow, deltas Row) watch.EventType { } return a } - -func (l *list) ensureDeletes(kk []string) { - // Check for deletions! - for k := range l.cache { - var found bool - for _, key := range kk { - if k == key { - found = true - break - } - } - if !found { - delete(l.cache, k) - } - } -} diff --git a/internal/views/app.go b/internal/views/app.go index c13fc8eb..012dac5b 100644 --- a/internal/views/app.go +++ b/internal/views/app.go @@ -99,7 +99,7 @@ func (a *appView) Init(version string, rate int) { if a.conn() != nil { ns, err := a.conn().Config().CurrentNamespaceName() if err != nil { - log.Info().Err(err).Msg("No namespace specified using all namespaces") + log.Info().Msg("No namespace specified using all namespaces") } a.startInformer(ns) a.clusterInfo().init(version)