103 lines
2.7 KiB
Go
103 lines
2.7 KiB
Go
package model
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/derailed/k9s/internal"
|
|
"github.com/derailed/k9s/internal/client"
|
|
"github.com/derailed/k9s/internal/render"
|
|
"github.com/rs/zerolog/log"
|
|
)
|
|
|
|
// Reconcile previous vs current state and emits delta events.
|
|
func Reconcile(ctx context.Context, table render.TableData, gvr client.GVR) (render.TableData, error) {
|
|
defer func(t time.Time) {
|
|
log.Debug().Msgf("RECONCILE elapsed: %v", time.Since(t))
|
|
}(time.Now())
|
|
|
|
path, ok := ctx.Value(internal.KeyPath).(string)
|
|
if !ok {
|
|
return table, fmt.Errorf("no path specified for %s", gvr)
|
|
}
|
|
log.Debug().Msgf("Reconcile %q in ns %q with path %q", gvr, table.Namespace, path)
|
|
factory, ok := ctx.Value(internal.KeyFactory).(Factory)
|
|
if !ok {
|
|
return table, fmt.Errorf("no factory found for %s", gvr)
|
|
}
|
|
m, ok := Registry[string(gvr)]
|
|
if !ok {
|
|
log.Warn().Msgf("Resource %s not found in registry. Going generic!", gvr)
|
|
m = ResourceMeta{
|
|
Model: &Generic{},
|
|
Renderer: &render.Generic{},
|
|
}
|
|
}
|
|
if m.Model == nil {
|
|
m.Model = &Resource{}
|
|
}
|
|
m.Model.Init(table.Namespace, string(gvr), factory)
|
|
|
|
table.Header = m.Renderer.Header(table.Namespace)
|
|
oo, err := m.Model.List(ctx)
|
|
if err != nil {
|
|
return table, err
|
|
}
|
|
log.Debug().Msgf("Model returned [%d] items", len(oo))
|
|
|
|
rows := make(render.Rows, len(oo))
|
|
if err := m.Model.Hydrate(oo, rows, m.Renderer); err != nil {
|
|
return table, err
|
|
}
|
|
update(&table, rows)
|
|
|
|
log.Debug().Msgf("Table returned [%d] events", len(table.RowEvents))
|
|
return table, nil
|
|
}
|
|
|
|
func update(table *render.TableData, rows render.Rows) {
|
|
cacheEmpty := len(table.RowEvents) == 0
|
|
kk := make([]string, 0, len(rows))
|
|
var blankDelta render.DeltaRow
|
|
for _, row := range rows {
|
|
kk = append(kk, row.ID)
|
|
if cacheEmpty {
|
|
table.RowEvents = append(table.RowEvents, render.NewRowEvent(render.EventAdd, row))
|
|
continue
|
|
}
|
|
if index, ok := table.RowEvents.FindIndex(row.ID); ok {
|
|
delta := render.NewDeltaRow(table.RowEvents[index].Row, row, table.Header.HasAge())
|
|
if delta.IsBlank() {
|
|
table.RowEvents[index].Kind, table.RowEvents[index].Deltas = render.EventUnchanged, blankDelta
|
|
} else {
|
|
table.RowEvents[index] = render.NewDeltaRowEvent(row, delta)
|
|
}
|
|
continue
|
|
}
|
|
table.RowEvents = append(table.RowEvents, render.NewRowEvent(render.EventAdd, row))
|
|
}
|
|
|
|
if cacheEmpty {
|
|
return
|
|
}
|
|
ensureDeletes(table, kk)
|
|
}
|
|
|
|
// EnsureDeletes delete items in cache that are no longer valid.
|
|
func ensureDeletes(table *render.TableData, newKeys []string) {
|
|
for _, re := range table.RowEvents {
|
|
var found bool
|
|
for i, key := range newKeys {
|
|
if key == re.Row.ID {
|
|
found = true
|
|
newKeys = append(newKeys[:i], newKeys[i+1:]...)
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
table.RowEvents = table.RowEvents.Delete(re.Row.ID)
|
|
}
|
|
}
|
|
}
|