diff --git a/Makefile b/Makefile index 65011237..9154aba6 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ NAME := k9s -VERSION ?= v0.50.11 +VERSION ?= v0.50.12 PACKAGE := github.com/derailed/$(NAME) OUTPUT_BIN ?= execs/${NAME} GO_FLAGS ?= diff --git a/change_logs/release_v0.50.12.md b/change_logs/release_v0.50.12.md new file mode 100644 index 00000000..eadc26ef --- /dev/null +++ b/change_logs/release_v0.50.12.md @@ -0,0 +1,29 @@ + + +# Release v0.50.12 + +## 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/zt-3360a389v-ElLHrb0Dp1kAXqYUItSAFA) + +## Maintenance Release! + +## Resolved Issues + +* [#3570](https://github.com/derailed/k9s/issues/3570) 0.50.11 could not display any resources +* [#3562](https://github.com/derailed/k9s/issues/3562) Can't delete namespace +* [#3547](https://github.com/derailed/k9s/issues/3547) Error message from admission controller + +--- + © 2025 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)# \ No newline at end of file diff --git a/internal/client/client.go b/internal/client/client.go index a012781a..125efca4 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -184,7 +184,7 @@ func (a *APIClient) CanI(ns string, gvr *GVR, name string, verbs []string) (auth slogs.Verb, verbs, ) if resp != nil { - clog.Debug("[CAN] reps", + clog.Debug("[CAN] response", slogs.AuthStatus, resp.Status.Allowed, slogs.AuthReason, resp.Status.Reason, ) @@ -196,7 +196,7 @@ func (a *APIClient) CanI(ns string, gvr *GVR, name string, verbs []string) (auth } if !resp.Status.Allowed { a.cache.Add(key, false, cacheExpiry) - return auth, fmt.Errorf("`%s access denied for user on %q:%s", v, ns, gvr) + return auth, fmt.Errorf("(%s) access denied for user on resource %q:%s in namespace %q", v, name, gvr, ns) } } auth = true diff --git a/internal/model/flash.go b/internal/model/flash.go index b98669c2..bb363536 100644 --- a/internal/model/flash.go +++ b/internal/model/flash.go @@ -14,7 +14,7 @@ import ( const ( // DefaultFlashDelay sets the flash clear delay. - DefaultFlashDelay = 3 * time.Second + DefaultFlashDelay = 6 * time.Second // FlashInfo represents an info message. FlashInfo FlashLevel = iota diff --git a/internal/view/browser.go b/internal/view/browser.go index 90d8dd02..57e44072 100644 --- a/internal/view/browser.go +++ b/internal/view/browser.go @@ -302,8 +302,8 @@ func (b *Browser) TableNoData(mdata *model1.TableData) { if !b.app.ConOK() || cancel == nil || !b.app.IsRunning() { return } - // Skip warning on first view or if table data is empty (likely during initialization) - if b.firstView.Load() == 0 || mdata.Empty() { + // Skip warning on first view (likely during initialization) + if b.firstView.Load() == 0 || mdata.HeaderCount() == 0 { b.firstView.Add(1) return } @@ -316,7 +316,7 @@ func (b *Browser) TableNoData(mdata *model1.TableData) { 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.app.Flash().Warnf("No resources found for %s in %q namespace", b.GVR(), client.PrintNamespace(b.GetNamespace())) } b.refreshActions() b.UpdateUI(cdata, mdata) diff --git a/internal/view/container.go b/internal/view/container.go index 26135f8e..61f0f334 100644 --- a/internal/view/container.go +++ b/internal/view/container.go @@ -164,9 +164,21 @@ func (c *Container) shellCmd(evt *tcell.EventKey) *tcell.EventKey { return evt } + var err error c.Stop() - defer c.Start() - shellIn(c.App(), c.GetTable().Path, path) + defer func() { + c.Start() + if err != nil { + c.App().QueueUpdate(func() { + if err != nil { + c.App().Flash().Errf("Shell exec failed: %s", err) + } + }) + + c.App().Flash().Err(err) + } + }() + err = shellIn(c.App(), c.GetTable().Path, path) return nil } diff --git a/internal/view/exec.go b/internal/view/exec.go index 60d79242..38eb60d0 100644 --- a/internal/view/exec.go +++ b/internal/view/exec.go @@ -587,7 +587,7 @@ func pipe(_ context.Context, opts *shellOpts, statusChan chan<- string, w, e *by close(statusChan) if err != nil { - err = fmt.Errorf("command failed. Check logs: %w", err) + err = fmt.Errorf("command failed. Check k9s logs: %w", err) } return err diff --git a/internal/view/pod.go b/internal/view/pod.go index 5bc6639c..9b3417bf 100644 --- a/internal/view/pod.go +++ b/internal/view/pod.go @@ -393,28 +393,33 @@ func containerShellIn(a *App, comp model.Component, path, co string) error { } func resumeShellIn(a *App, c model.Component, path, co string) { + var err error c.Stop() - defer c.Start() + defer func() { + c.Start() + a.QueueUpdate(func() { + if err != nil { + a.Flash().Errf("Shell exec failed: %s", err) + } + }) + }() - shellIn(a, path, co) + err = shellIn(a, path, co) } -func shellIn(a *App, fqn, co string) { +func shellIn(a *App, fqn, co string) error { platform, err := getPodOS(a.factory, fqn) if err != nil { - slog.Warn("OS detect failed", slogs.Error, err) + return err } - args := computeShellArgs(fqn, co, a.Conn().Config().Flags(), platform) + args := computeShellArgs(fqn, co, a.Conn().Config().Flags(), platform) c := color.New(color.BgGreen).Add(color.FgBlack).Add(color.Bold) - err = runK(a, &shellOpts{ + return runK(a, &shellOpts{ clear: true, banner: c.Sprintf(bannerFmt, fqn, co), args: args}, ) - if err != nil { - a.Flash().Errf("Shell exec failed: %s", err) - } } func containerAttachIn(a *App, comp model.Component, path, co string) error { diff --git a/internal/watch/factory.go b/internal/watch/factory.go index e65d1eb1..408239fb 100644 --- a/internal/watch/factory.go +++ b/internal/watch/factory.go @@ -201,7 +201,11 @@ func (f *Factory) isClusterWide() bool { // CanForResource return an informer is user has access. func (f *Factory) CanForResource(ns string, gvr *client.GVR, verbs []string) (informers.GenericInformer, error) { - auth, err := f.Client().CanI(ns, gvr, "", verbs) + var resName string + if gvr == client.NsGVR { + resName = ns + } + auth, err := f.Client().CanI(ns, gvr, resName, verbs) if err != nil { return nil, err } diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 96dc0f9c..6154f8b1 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -1,6 +1,6 @@ name: k9s base: core22 -version: 'v0.50.11' +version: 'v0.50.12' summary: K9s is a CLI to view and manage your Kubernetes clusters. 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.