refactor list

mine
derailed 2019-06-21 22:08:53 -06:00
parent eac37bbe6b
commit d6d5f32672
3 changed files with 90 additions and 91 deletions

View File

@ -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 {

View File

@ -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<container> %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)
}
}
}

View File

@ -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)