Rel v0.50.2 (#3269)
* fix#3266 dp alias fails * fix#3267 add no data flash * fix#3264 storage-class broke describe/yaml * fix#3260 po yaml crash * rel notesmine
parent
419a0ce6dc
commit
bc22b87053
2
Makefile
2
Makefile
|
|
@ -11,7 +11,7 @@ DATE ?= $(shell TZ=UTC date -j -f "%s" ${SOURCE_DATE_EPOCH} +"%Y-%m-%dT%H:
|
||||||
else
|
else
|
||||||
DATE ?= $(shell date -u -d @${SOURCE_DATE_EPOCH} +"%Y-%m-%dT%H:%M:%SZ")
|
DATE ?= $(shell date -u -d @${SOURCE_DATE_EPOCH} +"%Y-%m-%dT%H:%M:%SZ")
|
||||||
endif
|
endif
|
||||||
VERSION ?= v0.50.1
|
VERSION ?= v0.50.2
|
||||||
IMG_NAME := derailed/k9s
|
IMG_NAME := derailed/k9s
|
||||||
IMAGE := ${IMG_NAME}:${VERSION}
|
IMAGE := ${IMG_NAME}:${VERSION}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
<img src="https://raw.githubusercontent.com/derailed/k9s/master/assets/k9s.png" align="center" width="800" height="auto"/>
|
||||||
|
|
||||||
|
# Release v0.50.2
|
||||||
|
|
||||||
|
## 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!
|
||||||
|
Also big thanks to all that have allocated their own time to help others on both slack and on this repo!!
|
||||||
|
|
||||||
|
As you may know, K9s is not pimped out by corps with deep pockets, thus 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)
|
||||||
|
|
||||||
|
## 5-0, 5-0 HotFix!
|
||||||
|
|
||||||
|
It looks like we've broken a few (more) things in the clean up process 😳
|
||||||
|
This is what you get for trying to refresh a ~10 year old code base 🙀
|
||||||
|
Apologizes for the `disruption in the farce`. Hopefully much happier on v0.50.2...
|
||||||
|
Are we there yet? Crossing fingers AND toes...
|
||||||
|
|
||||||
|
☠️ Careful on this upgrade! 🏴☠️
|
||||||
|
We've gone thru lots of code revamp/refactor in the v0.50.0, so mileage may vary...
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Resolved Issues
|
||||||
|
|
||||||
|
* [#3267](https://github.com/derailed/k9s/issues/3267) Show some output or message when no resources are found
|
||||||
|
* [#3266](https://github.com/derailed/k9s/issues/3266) Command alias :dp fails with "no resource meta defined for deployments" error
|
||||||
|
* [#3264](https://github.com/derailed/k9s/issues/3264) can't execute get(y) or describe(d) in StorageClass view
|
||||||
|
* [#3260](https://github.com/derailed/k9s/issues/3260) yaml view of pod will crash the app (Boom!! cannot deep copy int. (Maybe??)
|
||||||
|
|
||||||
|
---
|
||||||
|
<img src="https://raw.githubusercontent.com/derailed/k9s/master/assets/imhotep_logo.png" width="32" height="auto"/> © 2025 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
|
@ -22,6 +22,14 @@ func IsClusterWide(ns string) bool {
|
||||||
return ns == NamespaceAll || ns == BlankNamespace || ns == ClusterScope
|
return ns == NamespaceAll || ns == BlankNamespace || ns == ClusterScope
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func PrintNamespace(ns string) string {
|
||||||
|
if IsAllNamespaces(ns) {
|
||||||
|
return "all"
|
||||||
|
}
|
||||||
|
|
||||||
|
return ns
|
||||||
|
}
|
||||||
|
|
||||||
// CleanseNamespace ensures all ns maps to blank.
|
// CleanseNamespace ensures all ns maps to blank.
|
||||||
func CleanseNamespace(ns string) string {
|
func CleanseNamespace(ns string) string {
|
||||||
if IsAllNamespace(ns) {
|
if IsAllNamespace(ns) {
|
||||||
|
|
|
||||||
|
|
@ -84,16 +84,14 @@ func (a *Aliases) Resolve(command string) (*client.GVR, string, bool) {
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, "", false
|
return nil, "", false
|
||||||
}
|
}
|
||||||
if agvr.IsCommand() {
|
|
||||||
p := cmd.NewInterpreter(agvr.String())
|
p := cmd.NewInterpreter(agvr.String())
|
||||||
gvr, ok := a.Get(p.Cmd())
|
gvr, ok := a.Get(p.Cmd())
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, "", false
|
return agvr, "", true
|
||||||
}
|
|
||||||
return gvr, p.Args(), true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return agvr, "", true
|
return gvr, p.Args(), true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get retrieves an alias.
|
// Get retrieves an alias.
|
||||||
|
|
|
||||||
|
|
@ -18,10 +18,13 @@ import (
|
||||||
|
|
||||||
func TestAsGVR(t *testing.T) {
|
func TestAsGVR(t *testing.T) {
|
||||||
a := dao.NewAlias(makeFactory())
|
a := dao.NewAlias(makeFactory())
|
||||||
a.Define(client.PodGVR, "po", "pod", "pods")
|
a.Define(client.PodGVR, "po", "pipo", "pod")
|
||||||
|
a.Define(client.PodGVR, client.PodGVR.String())
|
||||||
|
a.Define(client.PodGVR, client.PodGVR.AsResourceName())
|
||||||
a.Define(client.WkGVR, client.WkGVR.String(), "workload", "wkl")
|
a.Define(client.WkGVR, client.WkGVR.String(), "workload", "wkl")
|
||||||
a.Define(client.NewGVR("pod default"), "pp")
|
a.Define(client.NewGVR("pod default"), "pp")
|
||||||
a.Define(client.NewGVR("pod default @fred"), "ppc")
|
a.Define(client.NewGVR("pipo default"), "ppo")
|
||||||
|
a.Define(client.NewGVR("pod default app=fred @fred"), "ppc")
|
||||||
|
|
||||||
uu := map[string]struct {
|
uu := map[string]struct {
|
||||||
cmd string
|
cmd string
|
||||||
|
|
@ -29,40 +32,59 @@ func TestAsGVR(t *testing.T) {
|
||||||
gvr *client.GVR
|
gvr *client.GVR
|
||||||
exp string
|
exp string
|
||||||
}{
|
}{
|
||||||
"ok": {
|
"gvr": {
|
||||||
|
cmd: "v1/pods",
|
||||||
|
ok: true,
|
||||||
|
gvr: client.PodGVR,
|
||||||
|
},
|
||||||
|
|
||||||
|
"r": {
|
||||||
cmd: "pods",
|
cmd: "pods",
|
||||||
ok: true,
|
ok: true,
|
||||||
gvr: client.PodGVR,
|
gvr: client.PodGVR,
|
||||||
},
|
},
|
||||||
|
|
||||||
"ok-short": {
|
"alias1": {
|
||||||
cmd: "po",
|
cmd: "po",
|
||||||
ok: true,
|
ok: true,
|
||||||
gvr: client.PodGVR,
|
gvr: client.PodGVR,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"alias-2": {
|
||||||
|
cmd: "pipo",
|
||||||
|
ok: true,
|
||||||
|
gvr: client.PodGVR,
|
||||||
|
},
|
||||||
|
|
||||||
"missing": {
|
"missing": {
|
||||||
cmd: "zorg",
|
cmd: "zorg",
|
||||||
},
|
},
|
||||||
|
|
||||||
"alias": {
|
"no-args": {
|
||||||
cmd: "wkl",
|
cmd: "wkl",
|
||||||
ok: true,
|
ok: true,
|
||||||
gvr: client.WkGVR,
|
gvr: client.WkGVR,
|
||||||
},
|
},
|
||||||
|
|
||||||
"ns-alias": {
|
"ns-arg": {
|
||||||
cmd: "pp",
|
cmd: "pp",
|
||||||
ok: true,
|
ok: true,
|
||||||
gvr: client.PodGVR,
|
gvr: client.PodGVR,
|
||||||
exp: "default",
|
exp: "default",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"ns-inception": {
|
||||||
|
cmd: "ppo",
|
||||||
|
ok: true,
|
||||||
|
gvr: client.PodGVR,
|
||||||
|
exp: "default",
|
||||||
|
},
|
||||||
|
|
||||||
"full-alias": {
|
"full-alias": {
|
||||||
cmd: "ppc",
|
cmd: "ppc",
|
||||||
ok: true,
|
ok: true,
|
||||||
gvr: client.PodGVR,
|
gvr: client.PodGVR,
|
||||||
exp: "default @fred",
|
exp: "default app=fred @fred",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
"maps"
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
"github.com/derailed/k9s/internal/client"
|
"github.com/derailed/k9s/internal/client"
|
||||||
|
|
@ -85,15 +86,22 @@ func ToYAML(o runtime.Object, showManaged bool) (string, error) {
|
||||||
if o == nil {
|
if o == nil {
|
||||||
return "", errors.New("no object to yamlize")
|
return "", errors.New("no object to yamlize")
|
||||||
}
|
}
|
||||||
|
u, ok := o.(*unstructured.Unstructured)
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf("expecting unstructured but got %T", o)
|
||||||
|
}
|
||||||
|
if u.Object == nil {
|
||||||
|
return "", fmt.Errorf("expecting unstructured object but got nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
mm := u.Object
|
||||||
var (
|
var (
|
||||||
buff bytes.Buffer
|
buff bytes.Buffer
|
||||||
p printers.YAMLPrinter
|
p printers.YAMLPrinter
|
||||||
)
|
)
|
||||||
if !showManaged {
|
if !showManaged {
|
||||||
o = o.DeepCopyObject()
|
mm = maps.Clone(mm)
|
||||||
uo := o.(*unstructured.Unstructured).Object
|
if meta, ok := mm["metadata"].(map[string]any); ok {
|
||||||
if meta, ok := uo["metadata"].(map[string]any); ok {
|
|
||||||
delete(meta, "managedFields")
|
delete(meta, "managedFields")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -331,6 +331,9 @@ func loadPreferred(f Factory, m ResourceMetas) error {
|
||||||
if !isStandardGroup(r.GroupVersion) {
|
if !isStandardGroup(r.GroupVersion) {
|
||||||
res.Categories = append(res.Categories, crdCat)
|
res.Categories = append(res.Categories, crdCat)
|
||||||
}
|
}
|
||||||
|
if isScalable(gvr) {
|
||||||
|
res.Categories = append(res.Categories, scaleCat)
|
||||||
|
}
|
||||||
m[gvr] = &res
|
m[gvr] = &res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -342,6 +345,12 @@ func isStandardGroup(gv string) bool {
|
||||||
return stdGroups.Has(gv) || strings.Contains(gv, ".k8s.io")
|
return stdGroups.Has(gv) || strings.Contains(gv, ".k8s.io")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isScalable(gvr *client.GVR) bool {
|
||||||
|
ss := sets.New(client.DpGVR, client.StsGVR)
|
||||||
|
|
||||||
|
return ss.Has(gvr)
|
||||||
|
}
|
||||||
|
|
||||||
var deprecatedGVRs = sets.New(
|
var deprecatedGVRs = sets.New(
|
||||||
client.NewGVR("v1/events"),
|
client.NewGVR("v1/events"),
|
||||||
client.NewGVR("extensions/v1beta1/ingresses"),
|
client.NewGVR("extensions/v1beta1/ingresses"),
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,9 @@ package dao
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/derailed/k9s/internal"
|
"github.com/derailed/k9s/internal"
|
||||||
"github.com/derailed/k9s/internal/client"
|
"github.com/derailed/k9s/internal/client"
|
||||||
"github.com/derailed/k9s/internal/slogs"
|
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
|
|
@ -72,7 +69,6 @@ func (t *Table) List(ctx context.Context, ns string) ([]runtime.Object, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ti := time.Now()
|
|
||||||
o, err := c.Get().
|
o, err := c.Get().
|
||||||
SetHeader("Accept", header).
|
SetHeader("Accept", header).
|
||||||
Param("includeObject", includeObject).
|
Param("includeObject", includeObject).
|
||||||
|
|
@ -86,7 +82,6 @@ func (t *Table) List(ctx context.Context, ns string) ([]runtime.Object, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
slog.Debug("Q Time", slogs.Elapsed, time.Since(ti))
|
|
||||||
|
|
||||||
namespaced := true
|
namespaced := true
|
||||||
if res, e := MetaAccess.MetaFor(t.gvr); e == nil && !res.Namespaced {
|
if res, e := MetaAccess.MetaFor(t.gvr); e == nil && !res.Namespaced {
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ var Registry = map[string]ResourceMeta{
|
||||||
Renderer: new(render.Container),
|
Renderer: new(render.Container),
|
||||||
TreeRenderer: new(xray.Container),
|
TreeRenderer: new(xray.Container),
|
||||||
},
|
},
|
||||||
client.ScGVR.String(): {
|
client.ScnGVR.String(): {
|
||||||
DAO: new(dao.ImageScan),
|
DAO: new(dao.ImageScan),
|
||||||
Renderer: new(render.ImageScan),
|
Renderer: new(render.ImageScan),
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,9 @@ const initRefreshRate = 300 * time.Millisecond
|
||||||
|
|
||||||
// TableListener represents a table model listener.
|
// TableListener represents a table model listener.
|
||||||
type TableListener interface {
|
type TableListener interface {
|
||||||
|
// TableNoData notifies listener no data was found.
|
||||||
|
TableNoData(*model1.TableData)
|
||||||
|
|
||||||
// TableDataChanged notifies the model data changed.
|
// TableDataChanged notifies the model data changed.
|
||||||
TableDataChanged(*model1.TableData)
|
TableDataChanged(*model1.TableData)
|
||||||
|
|
||||||
|
|
@ -232,7 +235,12 @@ func (t *Table) refresh(ctx context.Context) error {
|
||||||
if err := t.reconcile(ctx); err != nil {
|
if err := t.reconcile(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
t.fireTableChanged(t.Peek())
|
data := t.Peek()
|
||||||
|
if data.RowCount() == 0 {
|
||||||
|
t.fireNoData(data)
|
||||||
|
} else {
|
||||||
|
t.fireTableChanged(data)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -292,6 +300,17 @@ func (t *Table) fireTableChanged(data *model1.TableData) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Table) fireNoData(data *model1.TableData) {
|
||||||
|
var ll []TableListener
|
||||||
|
t.mx.RLock()
|
||||||
|
ll = t.listeners
|
||||||
|
t.mx.RUnlock()
|
||||||
|
|
||||||
|
for _, l := range ll {
|
||||||
|
l.TableNoData(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (t *Table) fireTableLoadFailed(err error) {
|
func (t *Table) fireTableLoadFailed(err error) {
|
||||||
var ll []TableListener
|
var ll []TableListener
|
||||||
t.mx.RLock()
|
t.mx.RLock()
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,8 @@ type tableListener struct {
|
||||||
count, errs int
|
count, errs int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (*tableListener) TableNoData(*model1.TableData) {}
|
||||||
|
|
||||||
func (l *tableListener) TableDataChanged(*model1.TableData) {
|
func (l *tableListener) TableDataChanged(*model1.TableData) {
|
||||||
l.count++
|
l.count++
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/derailed/k9s/internal"
|
"github.com/derailed/k9s/internal"
|
||||||
|
|
@ -39,6 +40,7 @@ type Browser struct {
|
||||||
cancelFn context.CancelFunc
|
cancelFn context.CancelFunc
|
||||||
mx sync.RWMutex
|
mx sync.RWMutex
|
||||||
updating bool
|
updating bool
|
||||||
|
firstView atomic.Int32
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBrowser returns a new browser.
|
// NewBrowser returns a new browser.
|
||||||
|
|
@ -279,6 +281,36 @@ func (b *Browser) Aliases() sets.Set[string] {
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Model Protocol...
|
// Model Protocol...
|
||||||
|
|
||||||
|
// TableNoData notifies view no data is available.
|
||||||
|
func (b *Browser) TableNoData(data *model1.TableData) {
|
||||||
|
var cancel context.CancelFunc
|
||||||
|
b.mx.RLock()
|
||||||
|
cancel = b.cancelFn
|
||||||
|
b.mx.RUnlock()
|
||||||
|
|
||||||
|
if !b.app.ConOK() || cancel == nil || !b.app.IsRunning() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if b.firstView.Load() == 0 {
|
||||||
|
b.firstView.Add(1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cdata := b.Update(data, b.app.Conn().HasMetrics())
|
||||||
|
b.app.QueueUpdateDraw(func() {
|
||||||
|
if b.getUpdating() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
b.setUpdating(true)
|
||||||
|
defer b.setUpdating(false)
|
||||||
|
if b.GetColumnCount() == 0 {
|
||||||
|
b.app.Flash().Warnf("No resources found for %s in namespace %s", b.GVR(), client.PrintNamespace(b.GetNamespace()))
|
||||||
|
}
|
||||||
|
b.refreshActions()
|
||||||
|
b.UpdateUI(cdata, data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// TableDataChanged notifies view new data is available.
|
// TableDataChanged notifies view new data is available.
|
||||||
func (b *Browser) TableDataChanged(data *model1.TableData) {
|
func (b *Browser) TableDataChanged(data *model1.TableData) {
|
||||||
var cancel context.CancelFunc
|
var cancel context.CancelFunc
|
||||||
|
|
@ -297,6 +329,9 @@ func (b *Browser) TableDataChanged(data *model1.TableData) {
|
||||||
}
|
}
|
||||||
b.setUpdating(true)
|
b.setUpdating(true)
|
||||||
defer b.setUpdating(false)
|
defer b.setUpdating(false)
|
||||||
|
if b.GetColumnCount() == 0 {
|
||||||
|
b.app.Flash().Infof("Viewing %s in namespace %s", b.GVR(), client.PrintNamespace(b.GetNamespace()))
|
||||||
|
}
|
||||||
b.refreshActions()
|
b.refreshActions()
|
||||||
b.UpdateUI(cdata, data)
|
b.UpdateUI(cdata, data)
|
||||||
})
|
})
|
||||||
|
|
@ -488,7 +523,7 @@ func (b *Browser) switchNamespaceCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
b.setNamespace(ns)
|
b.setNamespace(ns)
|
||||||
b.app.Flash().Infof("Viewing namespace `%s`...", ns)
|
b.app.Flash().Infof("Viewing %s in namespace `%s`...", b.GVR(), client.PrintNamespace(ns))
|
||||||
b.refresh()
|
b.refresh()
|
||||||
b.UpdateTitle()
|
b.UpdateTitle()
|
||||||
b.SelectRow(1, 0, true)
|
b.SelectRow(1, 0, true)
|
||||||
|
|
@ -528,7 +563,7 @@ func (b *Browser) defaultContext() context.Context {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Browser) refreshActions() {
|
func (b *Browser) refreshActions() {
|
||||||
if b.App().Content.Top() != nil && b.App().Content.Top().Name() != b.Name() {
|
if top := b.App().Content.Top(); top != nil && top.Name() != b.Name() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
aa := ui.NewKeyActionsFromMap(ui.KeyMap{
|
aa := ui.NewKeyActionsFromMap(ui.KeyMap{
|
||||||
|
|
|
||||||
|
|
@ -344,7 +344,6 @@ func (c *Command) exec(p *cmd.Interpreter, gvr *client.GVR, comp model.Component
|
||||||
}
|
}
|
||||||
comp.SetCommand(p)
|
comp.SetCommand(p)
|
||||||
|
|
||||||
c.app.Flash().Infof("Viewing %s...", gvr)
|
|
||||||
if clearStack {
|
if clearStack {
|
||||||
cmd := contextRX.ReplaceAllString(p.GetLine(), "")
|
cmd := contextRX.ReplaceAllString(p.GetLine(), "")
|
||||||
c.app.Config.SetActiveView(cmd)
|
c.app.Config.SetActiveView(cmd)
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ func miscViewers(vv MetaViewers) {
|
||||||
vv[client.CoGVR] = MetaViewer{
|
vv[client.CoGVR] = MetaViewer{
|
||||||
viewerFn: NewContainer,
|
viewerFn: NewContainer,
|
||||||
}
|
}
|
||||||
vv[client.ScGVR] = MetaViewer{
|
vv[client.ScnGVR] = MetaViewer{
|
||||||
viewerFn: NewImageScan,
|
viewerFn: NewImageScan,
|
||||||
}
|
}
|
||||||
vv[client.PfGVR] = MetaViewer{
|
vv[client.PfGVR] = MetaViewer{
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ func (v *VulnerabilityExtender) bindKeys(aa *ui.KeyActions) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *VulnerabilityExtender) showVulCmd(*tcell.EventKey) *tcell.EventKey {
|
func (v *VulnerabilityExtender) showVulCmd(*tcell.EventKey) *tcell.EventKey {
|
||||||
isv := NewImageScan(client.ScGVR)
|
isv := NewImageScan(client.ScnGVR)
|
||||||
isv.SetContextFn(v.selContext)
|
isv.SetContextFn(v.selContext)
|
||||||
if err := v.App().inject(isv, false); err != nil {
|
if err := v.App().inject(isv, false); err != nil {
|
||||||
v.App().Flash().Err(err)
|
v.App().Flash().Err(err)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
name: k9s
|
name: k9s
|
||||||
base: core22
|
base: core22
|
||||||
version: 'v0.50.1'
|
version: 'v0.50.2'
|
||||||
summary: K9s is a CLI to view and manage your Kubernetes clusters.
|
summary: K9s is a CLI to view and manage your Kubernetes clusters.
|
||||||
description: |
|
description: |
|
||||||
K9s is a CLI to view and manage your Kubernetes clusters. By leveraging a terminal UI, you can easily traverse Kubernetes resources and view the state of your clusters in a single powerful session.
|
K9s is a CLI to view and manage your Kubernetes clusters. By leveraging a terminal UI, you can easily traverse Kubernetes resources and view the state of your clusters in a single powerful session.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue