release v0.25.11 (#1377)

mine
Fernand Galiana 2021-12-14 10:44:24 -07:00 committed by GitHub
parent e64dcbcbdc
commit 11c2ae2622
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
56 changed files with 293 additions and 317 deletions

View File

@ -5,7 +5,7 @@ PACKAGE := github.com/derailed/$(NAME)
GIT_REV ?= $(shell git rev-parse --short HEAD)
SOURCE_DATE_EPOCH ?= $(shell date +%s)
DATE ?= $(shell date -u -d @${SOURCE_DATE_EPOCH} +"%Y-%m-%dT%H:%M:%SZ")
VERSION ?= v0.25.10
VERSION ?= v0.25.11
IMG_NAME := derailed/k9s
IMAGE := ${IMG_NAME}:${VERSION}

View File

@ -0,0 +1,42 @@
<img src="https://raw.githubusercontent.com/derailed/k9s/master/assets/k9s_small.png" align="right" width="200" height="auto"/>
# Release v0.25.11
## Notes
Thank you to all that contributed with flushing out issues and enhancements for K9s! I'll try to mark some of these issues as fixed. But if you don't mind grab the latest rev and see if we're happier with some of the fixes! If you've filed an issue please help me verify and close. Your support, kindness and awesome suggestions to make K9s better are as ever very much noted and appreciated!
If you feel K9s is helping your Kubernetes journey, please consider joining our [sponsorship program](https://github.com/sponsors/derailed) and/or make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
On Slack? Please join us [K9slackers](https://join.slack.com/t/k9sers/shared_invite/enQtOTA5MDEyNzI5MTU0LWQ1ZGI3MzliYzZhZWEyNzYxYzA3NjE0YTk1YmFmNzViZjIyNzhkZGI0MmJjYzhlNjdlMGJhYzE2ZGU1NjkyNTM)
### A Word From Our Sponsors...
I want to recognize the following folks that have been kind enough to join our sponsorship program and opted to `pay it forward`!
* [Joshua Kapellen](https://github.com/joshuakapellen)
* [Qdentity](https://github.com/qdentity)
* [Maxim](https://github.com/bsod90)
* [Sönke Schau](https://github.com/xgcssch)
So if you feel K9s is helping with your productivity while administering your Kubernetes clusters, please consider pitching in as it will go a long way in ensuring a thriving environment for this repo and our k9ers community at large.
Also please take some time and give a huge shoot out to all the good folks below that have spent time plowing thru the code to help improve K9s for all of us!
Thank you!!
---
## Maintenance Release!
Hoy! end of year suck... Feeling the burn ;( Apologize for the disruptions...
---
## Resolved Issues
* [Issue #1374](https://github.com/derailed/k9s/issues/1374) --all-namespaces does not work v0.25.10
* [Issue #1376](https://github.com/derailed/k9s/issues/1376) Events not sorted correctly by dates
* [Issue #1373](https://github.com/derailed/k9s/issues/1373) change namespace not possible
<img src="https://raw.githubusercontent.com/derailed/k9s/master/assets/imhotep_logo.png" width="32" height="auto"/> © 2021 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)

View File

@ -23,9 +23,8 @@ const (
// Config tracks a kubernetes configuration.
type Config struct {
flags *genericclioptions.ConfigFlags
mutex *sync.RWMutex
OverrideNS bool
flags *genericclioptions.ConfigFlags
mutex *sync.RWMutex
}
// NewConfig returns a new k8s config or an error if the flags are invalid.
@ -183,15 +182,15 @@ func (c *Config) CurrentClusterName() (string, error) {
}
// ClusterNames fetch all kubeconfig defined clusters.
func (c *Config) ClusterNames() ([]string, error) {
func (c *Config) ClusterNames() (map[string]struct{}, error) {
cfg, err := c.RawConfig()
if err != nil {
return nil, err
}
cc := make([]string, 0, len(cfg.Clusters))
cc := make(map[string]struct{}, len(cfg.Clusters))
for name := range cfg.Clusters {
cc = append(cc, name)
cc[name] = struct{}{}
}
return cc, nil

View File

@ -36,15 +36,14 @@ type (
CurrentNamespaceName() (string, error)
// ClusterNames() returns all available cluster names.
ClusterNames() ([]string, error)
ClusterNames() (map[string]struct{}, error)
}
// Config tracks K9s configuration options.
Config struct {
K9s *K9s `yaml:"k9s"`
client client.Connection
settings KubeSettings
overrideNS bool
K9s *K9s `yaml:"k9s"`
client client.Connection
settings KubeSettings
}
)
@ -94,11 +93,10 @@ func (c *Config) Refine(flags *genericclioptions.ConfigFlags, k9sFlags *Flags, c
c.K9s.ActivateCluster()
var ns string
var override bool
if k9sFlags != nil && IsBoolSet(k9sFlags.AllNamespaces) {
ns, override = client.NamespaceAll, true
ns = client.NamespaceAll
} else if isSet(flags.Namespace) {
ns, override = *flags.Namespace, true
ns = *flags.Namespace
} else if context.Namespace != "" {
ns = context.Namespace
} else if cl := c.K9s.ActiveCluster(); cl != nil {
@ -109,7 +107,7 @@ func (c *Config) Refine(flags *genericclioptions.ConfigFlags, k9sFlags *Flags, c
if err := c.SetActiveNamespace(ns); err != nil {
return err
}
flags.Namespace, c.overrideNS = &ns, override
flags.Namespace = &ns
}
if isSet(flags.ClusterName) {
@ -142,6 +140,9 @@ func (c *Config) ActiveNamespace() string {
return "default"
}
cl := c.CurrentCluster()
if cl != nil && cl.Namespace != nil {
return cl.Namespace.Active
}
if cl == nil {
cl = NewCluster()
c.K9s.Clusters[c.K9s.CurrentCluster] = cl
@ -154,10 +155,6 @@ func (c *Config) ActiveNamespace() string {
return ns
}
if cl.Namespace != nil {
return cl.Namespace.Active
}
return "default"
}
@ -221,9 +218,6 @@ func (c *Config) GetConnection() client.Connection {
// SetConnection set an api server connection.
func (c *Config) SetConnection(conn client.Connection) {
c.client = conn
if c.client != nil && c.client.Config() != nil {
c.client.Config().OverrideNS = c.overrideNS
}
}
// Load K9s configuration from file.

View File

@ -198,7 +198,7 @@ func TestConfigSaveFile(t *testing.T) {
m.When(mk.CurrentContextName()).ThenReturn("minikube", nil)
m.When(mk.CurrentClusterName()).ThenReturn("minikube", nil)
m.When(mk.CurrentNamespaceName()).ThenReturn("default", nil)
m.When(mk.ClusterNames()).ThenReturn([]string{"minikube", "fred", "blee"}, nil)
m.When(mk.ClusterNames()).ThenReturn(map[string]struct{}{"minikube": {}, "fred": {}, "blee": {}}, nil)
m.When(mk.NamespaceNames(namespaces())).ThenReturn([]string{"default"})
cfg := config.NewConfig(mk)
@ -228,7 +228,7 @@ func TestConfigReset(t *testing.T) {
m.When(mk.CurrentContextName()).ThenReturn("blee", nil)
m.When(mk.CurrentClusterName()).ThenReturn("blee", nil)
m.When(mk.CurrentNamespaceName()).ThenReturn("default", nil)
m.When(mk.ClusterNames()).ThenReturn([]string{"blee"}, nil)
m.When(mk.ClusterNames()).ThenReturn(map[string]struct{}{"blee": {}}, nil)
m.When(mk.NamespaceNames(namespaces())).ThenReturn([]string{"default"})
cfg := config.NewConfig(mk)
@ -271,7 +271,7 @@ func (m *mockSettings) CurrentClusterName() (string, error) { return "", nil }
func (m *mockSettings) CurrentNamespaceName() (string, error) {
return *m.flags.Namespace, nil
}
func (m *mockSettings) ClusterNames() ([]string, error) { return nil, nil }
func (m *mockSettings) ClusterNames() (map[string]struct{}, error) { return nil, nil }
// ----------------------------------------------------------------------------
// Test Data...

View File

@ -194,9 +194,9 @@ func (k *K9s) validateClusters(c client.Connection, ks KubeSettings) {
if err != nil {
return
}
for key := range k.Clusters {
k.Clusters[key].Validate(c, ks)
if InList(cc, key) {
for key, cluster := range k.Clusters {
cluster.Validate(c, ks)
if _, ok := cc[key]; ok {
continue
}
if k.CurrentCluster == key {
@ -224,8 +224,8 @@ func (k *K9s) Validate(c client.Connection, ks KubeSettings) {
}
k.Thresholds.Validate(c, ks)
if ctx, err := ks.CurrentContextName(); err == nil && len(k.CurrentContext) == 0 {
k.CurrentContext = ctx
if context, err := ks.CurrentContextName(); err == nil && len(k.CurrentContext) == 0 {
k.CurrentContext = context
k.CurrentCluster = ""
}

View File

@ -66,7 +66,7 @@ func TestK9sValidate(t *testing.T) {
mk := NewMockKubeSettings()
m.When(mk.CurrentContextName()).ThenReturn("ctx1", nil)
m.When(mk.CurrentClusterName()).ThenReturn("c1", nil)
m.When(mk.ClusterNames()).ThenReturn([]string{"c1", "c2"}, nil)
m.When(mk.ClusterNames()).ThenReturn(map[string]struct{}{"c1": {}, "c2": {}}, nil)
m.When(mk.NamespaceNames(namespaces())).ThenReturn([]string{"default"})
c := config.NewK9s()
@ -90,7 +90,7 @@ func TestK9sValidateBlank(t *testing.T) {
mk := NewMockKubeSettings()
m.When(mk.CurrentContextName()).ThenReturn("ctx1", nil)
m.When(mk.CurrentClusterName()).ThenReturn("c1", nil)
m.When(mk.ClusterNames()).ThenReturn([]string{"c1", "c2"}, nil)
m.When(mk.ClusterNames()).ThenReturn(map[string]struct{}{"c1": {}, "c2": {}}, nil)
m.When(mk.NamespaceNames(namespaces())).ThenReturn([]string{"default"})
var c config.K9s

View File

@ -25,17 +25,17 @@ func NewMockKubeSettings(options ...pegomock.Option) *MockKubeSettings {
func (mock *MockKubeSettings) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh }
func (mock *MockKubeSettings) FailHandler() pegomock.FailHandler { return mock.fail }
func (mock *MockKubeSettings) ClusterNames() ([]string, error) {
func (mock *MockKubeSettings) ClusterNames() (map[string]struct{}, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockKubeSettings().")
}
params := []pegomock.Param{}
result := pegomock.GetGenericMockFrom(mock).Invoke("ClusterNames", params, []reflect.Type{reflect.TypeOf((*[]string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var ret0 []string
result := pegomock.GetGenericMockFrom(mock).Invoke("ClusterNames", params, []reflect.Type{reflect.TypeOf((*map[string]struct{})(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var ret0 map[string]struct{}
var ret1 error
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].([]string)
ret0 = result[0].(map[string]struct{})
}
if result[1] != nil {
ret1 = result[1].(error)

View File

@ -110,6 +110,10 @@ var Registry = map[string]ResourceMeta{
"v1/persistentvolumeclaims": {
Renderer: &render.PersistentVolumeClaim{},
},
"v1/events": {
DAO: &dao.Table{},
Renderer: &render.Event{},
},
// Apps...
"apps/v1/deployments": {

View File

@ -240,7 +240,7 @@ func (t *Table) reconcile(ctx context.Context) error {
var rows render.Rows
if len(oo) > 0 {
if _, ok := meta.Renderer.(*render.Generic); ok {
if meta.Renderer.IsGeneric() {
table, ok := oo[0].(*metav1beta1.Table)
if !ok {
return fmt.Errorf("expecting a meta table but got %T", oo[0])
@ -300,8 +300,13 @@ func hydrate(ns string, oo []runtime.Object, rr render.Rows, re Renderer) error
return nil
}
type Generic interface {
SetTable(*metav1beta1.Table)
Render(interface{}, string, *render.Row) error
}
func genericHydrate(ns string, table *metav1beta1.Table, rr render.Rows, re Renderer) error {
gr, ok := re.(*render.Generic)
gr, ok := re.(Generic)
if !ok {
return fmt.Errorf("expecting generic renderer but got %T", re)
}

View File

@ -84,6 +84,9 @@ type Component interface {
// Renderer represents a resource renderer.
type Renderer interface {
// IsGeneric identifies a generic handler.
IsGeneric() bool
// Render converts raw resources to tabular data.
Render(o interface{}, ns string, row *render.Row) error

View File

@ -10,11 +10,8 @@ import (
)
// Alias renders a aliases to screen.
type Alias struct{}
// ColorerFunc colors a resource row.
func (Alias) ColorerFunc() ColorerFunc {
return DefaultColorer
type Alias struct {
Base
}
// Header returns a header row.

26
internal/render/base.go Normal file
View File

@ -0,0 +1,26 @@
package render
// DecoratorFunc decorates a string.
type DecoratorFunc func(string) string
// AgeDecorator represents a timestamped as human column.
var AgeDecorator = func(a string) string {
return toAgeHuman(a)
}
type Base struct{}
// IsGeneric identifies a generic handler.
func (Base) IsGeneric() bool {
return false
}
// ColorerFunc colors a resource row.
func (Base) ColorerFunc() ColorerFunc {
return DefaultColorer
}
// Happy returns true if resource is happy, false otherwise.
func (Base) Happy(_ string, _ Row) bool {
return true
}

View File

@ -24,7 +24,9 @@ var (
)
// Benchmark renders a benchmarks to screen.
type Benchmark struct{}
type Benchmark struct {
Base
}
// ColorerFunc colors a resource row.
func (b Benchmark) ColorerFunc() ColorerFunc {

View File

@ -35,7 +35,9 @@ type ContainerWithMetrics interface {
}
// Container renders a K8s Container to screen.
type Container struct{}
type Container struct {
Base
}
// ColorerFunc colors a resource row.
func (c Container) ColorerFunc() ColorerFunc {

View File

@ -12,7 +12,9 @@ import (
)
// Context renders a K8s ConfigMap to screen.
type Context struct{}
type Context struct {
Base
}
// ColorerFunc colors a resource row.
func (Context) ColorerFunc() ColorerFunc {

View File

@ -10,11 +10,8 @@ import (
)
// ClusterRole renders a K8s ClusterRole to screen.
type ClusterRole struct{}
// ColorerFunc colors a resource row.
func (ClusterRole) ColorerFunc() ColorerFunc {
return DefaultColorer
type ClusterRole struct {
Base
}
// Header returns a header rbw.

View File

@ -10,11 +10,8 @@ import (
)
// ClusterRoleBinding renders a K8s ClusterRoleBinding to screen.
type ClusterRoleBinding struct{}
// ColorerFunc colors a resource row.
func (ClusterRoleBinding) ColorerFunc() ColorerFunc {
return DefaultColorer
type ClusterRoleBinding struct {
Base
}
// Header returns a header rbw.

View File

@ -11,11 +11,8 @@ import (
)
// CustomResourceDefinition renders a K8s CustomResourceDefinition to screen.
type CustomResourceDefinition struct{}
// ColorerFunc colors a resource row.
func (CustomResourceDefinition) ColorerFunc() ColorerFunc {
return DefaultColorer
type CustomResourceDefinition struct {
Base
}
// Header returns a header rbw.

View File

@ -13,11 +13,8 @@ import (
)
// CronJob renders a K8s CronJob to screen.
type CronJob struct{}
// ColorerFunc colors a resource row.
func (CronJob) ColorerFunc() ColorerFunc {
return DefaultColorer
type CronJob struct {
Base
}
// Header returns a header row.

View File

@ -12,6 +12,11 @@ import (
// Dir renders a directory entry to screen.
type Dir struct{}
// IsGeneric identifies a generic handler.
func (Dir) IsGeneric() bool {
return false
}
// ColorerFunc colors a resource row.
func (Dir) ColorerFunc() ColorerFunc {
return func(ns string, _ Header, re RowEvent) tcell.Color {

View File

@ -12,7 +12,9 @@ import (
)
// Deployment renders a K8s Deployment to screen.
type Deployment struct{}
type Deployment struct {
Base
}
// ColorerFunc colors a resource row.
func (d Deployment) ColorerFunc() ColorerFunc {

View File

@ -12,11 +12,8 @@ import (
)
// DaemonSet renders a K8s DaemonSet to screen.
type DaemonSet struct{}
// ColorerFunc colors a resource row.
func (d DaemonSet) ColorerFunc() ColorerFunc {
return DefaultColorer
type DaemonSet struct {
Base
}
// Header returns a header row.

View File

@ -12,11 +12,8 @@ import (
)
// Endpoints renders a K8s Endpoints to screen.
type Endpoints struct{}
// ColorerFunc colors a resource row.
func (Endpoints) ColorerFunc() ColorerFunc {
return DefaultColorer
type Endpoints struct {
Base
}
// Header returns a header row.

View File

@ -1,35 +1,25 @@
package render
import (
"fmt"
"strings"
"github.com/derailed/k9s/internal/client"
"github.com/gdamore/tcell/v2"
metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1"
)
// BOZO!!
// import (
// "errors"
// "fmt"
// "strconv"
// "strings"
// "time"
// "github.com/derailed/k9s/internal/client"
// "github.com/derailed/tview"
// "github.com/gdamore/tcell/v2"
// v1 "k8s.io/api/core/v1"
// metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
// "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
// "k8s.io/apimachinery/pkg/runtime"
// "k8s.io/apimachinery/pkg/util/duration"
// api "k8s.io/kubernetes/pkg/apis/core"
// )
// Event renders a K8s Event to screen.
type Event struct{}
type Event struct {
Generic
}
func (*Event) IsGeneric() bool {
return true
}
// ColorerFunc colors a resource row.
func (e Event) ColorerFunc() ColorerFunc {
func (e *Event) ColorerFunc() ColorerFunc {
return func(ns string, h Header, re RowEvent) tcell.Color {
if !Happy(ns, h, re.Row) {
return ErrColor
@ -46,128 +36,63 @@ func (e Event) ColorerFunc() ColorerFunc {
}
}
// // Header returns a header rbw.
// func (Event) Header(ns string) Header {
// return Header{
// HeaderColumn{Name: "NAMESPACE"},
// HeaderColumn{Name: "LAST SEEN"},
// HeaderColumn{Name: "TYPE"},
// HeaderColumn{Name: "REASON"},
// HeaderColumn{Name: "OBJECT"},
// HeaderColumn{Name: "SUBOBJECT"},
// HeaderColumn{Name: "SOURCE"},
// HeaderColumn{Name: "MESSAGE", Wide: true},
// HeaderColumn{Name: "FIRST SEEN", Wide: true},
// HeaderColumn{Name: "COUNT", Align: tview.AlignRight},
// HeaderColumn{Name: "NAME"},
// HeaderColumn{Name: "VALID", Wide: true},
// }
// }
var ageCols = map[string]struct{}{
"FIRST SEEN": {},
"LAST SEEN": {},
}
// // Render renders a K8s resource to screen.
// func (e Event) Render(o interface{}, ns string, r *Row) error {
// raw, ok := o.(*unstructured.Unstructured)
// if !ok {
// return fmt.Errorf("Expected Event, but got %T", o)
// }
// var ev api.Event
// err := runtime.DefaultUnstructuredConverter.FromUnstructured(raw.Object, &ev)
// if err != nil {
// return err
// }
var wideCols = map[string]struct{}{
"SUBOBJECT": {},
"SOURCE": {},
"FIRST SEEN": {},
"NAME": {},
"MESSAGE": {},
}
// firstTimestamp := translateTimestampSince(ev.FirstTimestamp)
// if ev.FirstTimestamp.IsZero() {
// firstTimestamp = translateMicroTimestampSince(ev.EventTime)
// }
func (e *Event) Header(ns string) Header {
if e.table == nil {
return Header{}
}
hh := make(Header, 0, len(e.table.ColumnDefinitions))
hh = append(hh, HeaderColumn{Name: "NAMESPACE"})
for _, h := range e.table.ColumnDefinitions {
header := HeaderColumn{Name: strings.ToUpper(h.Name)}
if _, ok := ageCols[header.Name]; ok {
header.Time = true
}
if _, ok := wideCols[header.Name]; ok {
header.Wide = true
}
hh = append(hh, header)
}
// lastTimestamp := translateTimestampSince(ev.LastTimestamp)
// if ev.LastTimestamp.IsZero() {
// lastTimestamp = firstTimestamp
// }
// count := ev.Count
// if ev.Series != nil {
// lastTimestamp = translateMicroTimestampSince(ev.Series.LastObservedTime)
// count = ev.Series.Count
// } else if count == 0 {
// // Singleton events don't have a count set in the new API.
// count = 1
// }
return hh
}
// var target string
// if len(ev.InvolvedObject.Name) > 0 {
// target = fmt.Sprintf("%s/%s", strings.ToLower(ev.InvolvedObject.Kind), ev.InvolvedObject.Name)
// } else {
// target = strings.ToLower(ev.InvolvedObject.Kind)
// }
// Render renders a K8s resource to screen.
func (e *Event) Render(o interface{}, ns string, r *Row) error {
row, ok := o.(metav1beta1.TableRow)
if !ok {
return fmt.Errorf("expecting a TableRow but got %T", o)
}
nns, name, err := resourceNS(row.Object.Raw)
if err != nil {
return err
}
// r.ID = client.MetaFQN(ev.ObjectMeta)
// r.Fields = Fields{
// ev.Namespace,
// lastTimestamp,
// ev.Type,
// ev.Reason,
// target,
// ev.InvolvedObject.FieldPath,
// fmtEventSource(ev.Source, ev.ReportingController, ev.ReportingInstance),
// strings.TrimSpace(ev.Message),
// firstTimestamp,
// strconv.Itoa(int(count)),
// ev.Name,
// asStatus(e.diagnose(ev.Type)),
// }
if !ok {
return fmt.Errorf("expecting row 0 to be a string but got %T", row.Cells[0])
}
r.ID = client.FQN(nns, name)
r.Fields = make(Fields, 0, len(e.Header(ns)))
r.Fields = append(r.Fields, nns)
for _, c := range row.Cells {
if c == nil {
r.Fields = append(r.Fields, Blank)
continue
}
r.Fields = append(r.Fields, fmt.Sprintf("%v", c))
}
// return nil
// }
// func translateMicroTimestampSince(timestamp metav1.MicroTime) string {
// if timestamp.IsZero() {
// return "<unknown>"
// }
// return duration.HumanDuration(time.Since(timestamp.Time))
// }
// func translateTimestampSince(timestamp metav1.Time) string {
// if timestamp.IsZero() {
// return "<unknown>"
// }
// return duration.HumanDuration(time.Since(timestamp.Time))
// }
// func fmtEventSource(es api.EventSource, reportingController, reportingInstance string) string {
// return fmtEventSourceComponentInstance(
// firstNonEmpty(es.Component, reportingController),
// firstNonEmpty(es.Host, reportingInstance),
// )
// }
// func fmtEventSourceComponentInstance(component, instance string) string {
// if len(instance) == 0 {
// return component
// }
// return component + ", " + instance
// }
// func firstNonEmpty(ss ...string) string {
// for _, s := range ss {
// if len(s) > 0 {
// return s
// }
// }
// return ""
// }
// // Happy returns true if resource is happy, false otherwise.
// func (Event) diagnose(kind string) error {
// if kind != "Normal" {
// return errors.New("failed event")
// }
// return nil
// }
// // Helpers...
// func asRef(r v1.ObjectReference) string {
// return strings.ToLower(r.Kind) + ":" + r.Name
// }
return nil
}

View File

@ -14,13 +14,13 @@ const ageTableCol = "Age"
// Generic renders a generic resource to screen.
type Generic struct {
Base
table *metav1beta1.Table
ageIndex int
}
// Happy returns true if resource is happy, false otherwise.
func (Generic) Happy(ns string, r Row) bool {
func (*Generic) IsGeneric() bool {
return true
}
@ -30,7 +30,7 @@ func (g *Generic) SetTable(t *metav1beta1.Table) {
}
// ColorerFunc colors a resource row.
func (Generic) ColorerFunc() ColorerFunc {
func (*Generic) ColorerFunc() ColorerFunc {
return DefaultColorer
}

View File

@ -15,6 +15,11 @@ import (
// Helm renders a helm chart to screen.
type Helm struct{}
// IsGeneric identifies a generic handler.
func (Helm) IsGeneric() bool {
return false
}
// ColorerFunc colors a resource row.
func (Helm) ColorerFunc() ColorerFunc {
return func(ns string, h Header, re RowEvent) tcell.Color {

View File

@ -15,11 +15,8 @@ import (
)
// HorizontalPodAutoscaler renders a K8s HorizontalPodAutoscaler to screen.
type HorizontalPodAutoscaler struct{}
// ColorerFunc colors a resource row.
func (HorizontalPodAutoscaler) ColorerFunc() ColorerFunc {
return DefaultColorer
type HorizontalPodAutoscaler struct {
Base
}
// Header returns a header row.

View File

@ -16,11 +16,8 @@ import (
)
// Job renders a K8s Job to screen.
type Job struct{}
// ColorerFunc colors a resource row.
func (Job) ColorerFunc() ColorerFunc {
return DefaultColorer
type Job struct {
Base
}
// Header returns a header row.

View File

@ -22,11 +22,8 @@ const (
)
// Node renders a K8s Node to screen.
type Node struct{}
// ColorerFunc colors a resource row.
func (n Node) ColorerFunc() ColorerFunc {
return DefaultColorer
type Node struct {
Base
}
// Header returns a header row.

View File

@ -12,11 +12,8 @@ import (
)
// NetworkPolicy renders a K8s NetworkPolicy to screen.
type NetworkPolicy struct{}
// ColorerFunc colors a resource row.
func (NetworkPolicy) ColorerFunc() ColorerFunc {
return DefaultColorer
type NetworkPolicy struct {
Base
}
// Header returns a header row.

View File

@ -13,7 +13,9 @@ import (
)
// Namespace renders a K8s Namespace to screen.
type Namespace struct{}
type Namespace struct {
Base
}
// ColorerFunc colors a resource row.
func (n Namespace) ColorerFunc() ColorerFunc {

View File

@ -13,11 +13,8 @@ import (
)
// PodDisruptionBudget renders a K8s PodDisruptionBudget to screen.
type PodDisruptionBudget struct{}
// ColorerFunc colors a resource row.
func (p PodDisruptionBudget) ColorerFunc() ColorerFunc {
return DefaultColorer
type PodDisruptionBudget struct {
Base
}
// Header returns a header row.

View File

@ -17,7 +17,9 @@ import (
)
// Pod renders a K8s Pod to screen.
type Pod struct{}
type Pod struct {
Base
}
// ColorerFunc colors a resource row.
func (p Pod) ColorerFunc() ColorerFunc {

View File

@ -24,7 +24,9 @@ func rbacVerbHeader() Header {
}
// Policy renders a rbac policy to screen.
type Policy struct{}
type Policy struct {
Base
}
// ColorerFunc colors a resource row.
func (Policy) ColorerFunc() ColorerFunc {

View File

@ -15,7 +15,9 @@ import (
)
// Popeye renders a sanitizer to screen.
type Popeye struct{}
type Popeye struct {
Base
}
// ColorerFunc colors a resource row.
func (Popeye) ColorerFunc() ColorerFunc {

View File

@ -32,7 +32,9 @@ type Forwarder interface {
}
// PortForward renders a portforwards to screen.
type PortForward struct{}
type PortForward struct {
Base
}
// ColorerFunc colors a resource row.
func (PortForward) ColorerFunc() ColorerFunc {

View File

@ -13,7 +13,9 @@ import (
)
// PersistentVolume renders a K8s PersistentVolume to screen.
type PersistentVolume struct{}
type PersistentVolume struct {
Base
}
// ColorerFunc colors a resource row.
func (p PersistentVolume) ColorerFunc() ColorerFunc {

View File

@ -10,11 +10,8 @@ import (
)
// PersistentVolumeClaim renders a K8s PersistentVolumeClaim to screen.
type PersistentVolumeClaim struct{}
// ColorerFunc colors a resource row.
func (p PersistentVolumeClaim) ColorerFunc() ColorerFunc {
return DefaultColorer
type PersistentVolumeClaim struct {
Base
}
// Header returns a header rbw.

View File

@ -30,7 +30,9 @@ var (
)
// Rbac renders a rbac to screen.
type Rbac struct{}
type Rbac struct {
Base
}
// ColorerFunc colors a resource row.
func (Rbac) ColorerFunc() ColorerFunc {

View File

@ -10,7 +10,9 @@ import (
)
// Reference renders a reference to screen.
type Reference struct{}
type Reference struct {
Base
}
// ColorerFunc colors a resource row.
func (Reference) ColorerFunc() ColorerFunc {

View File

@ -10,11 +10,8 @@ import (
)
// Role renders a K8s Role to screen.
type Role struct{}
// ColorerFunc colors a resource row.
func (Role) ColorerFunc() ColorerFunc {
return DefaultColorer
type Role struct {
Base
}
// Header returns a header row.

View File

@ -11,11 +11,8 @@ import (
)
// RoleBinding renders a K8s RoleBinding to screen.
type RoleBinding struct{}
// ColorerFunc colors a resource row.
func (RoleBinding) ColorerFunc() ColorerFunc {
return DefaultColorer
type RoleBinding struct {
Base
}
// Header returns a header rbw.

View File

@ -12,7 +12,9 @@ import (
)
// ReplicaSet renders a K8s ReplicaSet to screen.
type ReplicaSet struct{}
type ReplicaSet struct {
Base
}
// ColorerFunc colors a resource row.
func (r ReplicaSet) ColorerFunc() ColorerFunc {

View File

@ -11,11 +11,8 @@ import (
)
// ServiceAccount renders a K8s ServiceAccount to screen.
type ServiceAccount struct{}
// ColorerFunc colors a resource row.
func (ServiceAccount) ColorerFunc() ColorerFunc {
return DefaultColorer
type ServiceAccount struct {
Base
}
// Header returns a header row.

View File

@ -10,11 +10,8 @@ import (
)
// StorageClass renders a K8s StorageClass to screen.
type StorageClass struct{}
// ColorerFunc colors a resource row.
func (StorageClass) ColorerFunc() ColorerFunc {
return DefaultColorer
type StorageClass struct {
Base
}
// Header returns a header row.

View File

@ -12,7 +12,9 @@ import (
)
// ScreenDump renders a screendumps to screen.
type ScreenDump struct{}
type ScreenDump struct {
Base
}
// ColorerFunc colors a resource row.
func (ScreenDump) ColorerFunc() ColorerFunc {
@ -21,14 +23,6 @@ func (ScreenDump) ColorerFunc() ColorerFunc {
}
}
// DecoratorFunc decorates a string.
type DecoratorFunc func(string) string
// AgeDecorator represents a timestamped as human column.
var AgeDecorator = func(a string) string {
return toAgeHuman(a)
}
// Header returns a header row.
func (ScreenDump) Header(ns string) Header {
return Header{

View File

@ -11,11 +11,8 @@ import (
)
// StatefulSet renders a K8s StatefulSet to screen.
type StatefulSet struct{}
// ColorerFunc colors a resource row.
func (s StatefulSet) ColorerFunc() ColorerFunc {
return DefaultColorer
type StatefulSet struct {
Base
}
// Header returns a header row.

View File

@ -9,11 +9,8 @@ import (
)
// Subject renders a rbac to screen.
type Subject struct{}
// Happy returns true if resource is happy, false otherwise.
func (Subject) Happy(_ string, _ Row) bool {
return true
type Subject struct {
Base
}
// ColorerFunc colors a resource row.

View File

@ -13,11 +13,8 @@ import (
)
// Service renders a K8s Service to screen.
type Service struct{}
// ColorerFunc colors a resource row.
func (Service) ColorerFunc() ColorerFunc {
return DefaultColorer
type Service struct {
Base
}
// Header returns a header row.

View File

@ -88,8 +88,8 @@ func (k ks) CurrentNamespaceName() (string, error) {
return "test", nil
}
func (k ks) ClusterNames() ([]string, error) {
return []string{"test"}, nil
func (k ks) ClusterNames() (map[string]struct{}, error) {
return map[string]struct{}{"test": {}}, nil
}
func (k ks) NamespaceNames(nn []v1.Namespace) []string {

View File

@ -276,10 +276,10 @@ func (a *App) Resume() {
go a.clusterUpdater(ctx)
if err := a.StylesWatcher(ctx, a); err != nil {
log.Error().Err(err).Msgf("Styles watcher failed")
log.Warn().Err(err).Msgf("Styles watcher failed")
}
if err := a.CustomViewsWatcher(ctx, a); err != nil {
log.Error().Err(err).Msgf("CustomView watcher failed")
log.Warn().Err(err).Msgf("CustomView watcher failed")
}
}
@ -357,6 +357,10 @@ func (a *App) switchNS(ns string) error {
if ns == client.ClusterScope {
ns = client.AllNamespaces
}
if ns == a.Config.ActiveNamespace() {
return nil
}
ok, err := a.isValidNS(ns)
if err != nil {
return err
@ -365,7 +369,10 @@ func (a *App) switchNS(ns string) error {
return fmt.Errorf("Invalid namespace %q", ns)
}
if err := a.Config.SetActiveNamespace(ns); err != nil {
return fmt.Errorf("Unable to save active namespace in config")
return err
}
if err := a.Config.Save(); err != nil {
return err
}
return a.factory.SetActiveNS(ns)

View File

@ -134,9 +134,6 @@ func (b *Browser) Start() {
if err := b.app.switchNS(ns); err != nil {
log.Error().Err(err).Msgf("ns switch failed")
}
if err := b.app.Config.Save(); err != nil {
log.Error().Err(err).Msgf("Config Save")
}
b.Stop()
b.GetModel().AddListener(b)

View File

@ -17,7 +17,8 @@ func NewEvent(gvr client.GVR) ResourceViewer {
e := Event{
ResourceViewer: NewBrowser(gvr),
}
e.GetTable().SetColorerFn(render.Event{}.ColorerFunc())
var r *render.Event
e.GetTable().SetColorerFn(r.ColorerFunc())
e.AddBindKeysFn(e.bindKeys)
e.GetTable().SetSortCol("LAST SEEN", false)
@ -25,9 +26,10 @@ func NewEvent(gvr client.GVR) ResourceViewer {
}
func (e *Event) bindKeys(aa ui.KeyActions) {
aa.Delete(tcell.KeyCtrlD, ui.KeyE)
aa.Delete(tcell.KeyCtrlD, ui.KeyE, ui.KeyA)
aa.Add(ui.KeyActions{
ui.KeyShiftL: ui.NewKeyAction("Sort LastSeen", e.GetTable().SortColCmd("LAST SEEN", false), false),
ui.KeyShiftF: ui.NewKeyAction("Sort FirstSeen", e.GetTable().SortColCmd("FIRST SEEN", false), false),
ui.KeyShiftT: ui.NewKeyAction("Sort Type", e.GetTable().SortColCmd("TYPE", true), false),
ui.KeyShiftR: ui.NewKeyAction("Sort Reason", e.GetTable().SortColCmd("REASON", true), false),
ui.KeyShiftS: ui.NewKeyAction("Sort Source", e.GetTable().SortColCmd("SOURCE", true), false),

View File

@ -171,8 +171,8 @@ func (k ks) CurrentNamespaceName() (string, error) {
return "test", nil
}
func (k ks) ClusterNames() ([]string, error) {
return []string{"test"}, nil
func (k ks) ClusterNames() (map[string]struct{}, error) {
return map[string]struct{}{"test": {}}, nil
}
func (k ks) NamespaceNames(nn []v1.Namespace) []string {

View File

@ -10,7 +10,9 @@ import (
)
// Section represents an xray renderer.
type Section struct{}
type Section struct {
render.Base
}
// Render renders an xray node.
func (s *Section) Render(ctx context.Context, ns string, o interface{}) error {