From d3027c8f2916b23606f647f47b434b08fc34bdf8 Mon Sep 17 00:00:00 2001 From: Fernand Galiana Date: Wed, 20 Mar 2024 13:00:34 -0600 Subject: [PATCH] K9s/release v0.32.4 (#2637) * [Bug] fix #2605 * [Bug] fix #2604 * [Bug] fix #2592 * [Bug] fix #2608 * [Bug] Fix #2612 * Rel v0.32.4 --- Makefile | 2 +- change_logs/release_v0.32.4.md | 65 +++++++++++++++++++++++ internal/client/client.go | 6 +-- internal/config/data/context.go | 4 ++ internal/config/data/ns.go | 1 + internal/config/json/schemas/plugins.json | 1 + internal/config/plugin.go | 1 + internal/dao/pod.go | 18 +++---- internal/render/sts.go | 10 ++-- internal/view/actions.go | 21 +++++--- internal/view/app.go | 21 ++------ internal/view/details.go | 1 + internal/view/dp.go | 41 ++------------ internal/view/ds.go | 38 ++++++++++--- internal/view/job.go | 29 +++++++++- internal/view/logs_extender.go | 26 +++++++++ internal/view/pod.go | 25 ++------- internal/view/sts.go | 33 +----------- plugins/debug-container.yaml | 1 + plugins/helm-purge.yaml | 1 + plugins/job-suspend.yaml | 1 + plugins/k3d-root-shell.yaml | 1 + plugins/liveMigration.yaml | 3 +- plugins/remove-finalizers.yaml | 3 +- plugins/rm-ns.yaml | 1 + snap/snapcraft.yaml | 2 +- 26 files changed, 214 insertions(+), 142 deletions(-) create mode 100644 change_logs/release_v0.32.4.md diff --git a/Makefile b/Makefile index 59c702504b..a1b57045fc 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ DATE ?= $(shell TZ=UTC date -j -f "%s" ${SOURCE_DATE_EPOCH} +"%Y-%m-%dT%H: else DATE ?= $(shell date -u -d @${SOURCE_DATE_EPOCH} +"%Y-%m-%dT%H:%M:%SZ") endif -VERSION ?= v0.32.3 +VERSION ?= v0.32.4 IMG_NAME := derailed/k9s IMAGE := ${IMG_NAME}:${VERSION} diff --git a/change_logs/release_v0.32.4.md b/change_logs/release_v0.32.4.md new file mode 100644 index 0000000000..15d012321d --- /dev/null +++ b/change_logs/release_v0.32.4.md @@ -0,0 +1,65 @@ + + +# Release v0.32.4 + +## 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) + +## Maintenance Release! + +--- + +## ♫ Sounds Behind The Release ♭ + +Thinking of all you at KubeCon Paris!! +May I suggest a nice glass of `cold Merlote` or other fine grape juices from my country? + +* [Le Gorille - George Brassens](https://www.youtube.com/watch?v=KVfwvk_yVyA) +* [Les Funerailles D'antan (Love this guy!) - George Brassens](https://www.youtube.com/watch?v=bwb5k4k2EMc) +* [Poinconneur Des Lilas - Serge Gainsbourg](https://www.youtube.com/watch?v=eWkWCFzkOvU) +* [Mon Legionaire (Yup! same guy??) - Serge Gainsbourg](https://www.youtube.com/watch?v=gl8gopryqWI) +* [Les Cornichons - Nino Ferrer](https://www.youtube.com/watch?v=N7JSW4NhM8I) +* [Paris s'eveille - Jacques Dutronc](https://www.youtube.com/watch?v=3WcCg6rm3uM) + +--- + +## Videos Are In The Can! + +Please dial [K9s Channel](https://www.youtube.com/channel/UC897uwPygni4QIjkPCpgjmw) for up coming content... + +* [K9s v0.31.0 Configs+Sneak peek](https://youtu.be/X3444KfjguE) +* [K9s v0.30.0 Sneak peek](https://youtu.be/mVBc1XneRJ4) +* [Vulnerability Scans](https://youtu.be/ULkl0MsaidU) + +--- + +## Resolved Issues + +* [#2608](https://github.com/derailed/k9s/issues/2608) Make the sanitize feature easier to use +* [#2605](https://github.com/derailed/k9s/issues/2605) Built-in shortcuts being overridden by plugins result in excessive logging +* [#2604](https://github.com/derailed/k9s/issues/2604) Ability to mark a plugin as Dangerous/destructive +* [#2592](https://github.com/derailed/k9s/issues/2592) "list access denied" when switching contexts within k9s since 0.32.0 + +--- + +## Contributed PRs + +Please be sure to give `Big Thanks!` and `ATTA Girls/Boys!` to all the fine contributors for making K9s better for all of us!! + +* [#2621](https://github.com/derailed/k9s/pull/2621) Fix snap build + +--- + + © 2024 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 9a39f583d7..e43a561aa6 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -217,10 +217,10 @@ func (a *APIClient) ServerVersion() (*version.Info, error) { return info, nil } -func (a *APIClient) IsValidNamespace(n string) bool { - ok, err := a.isValidNamespace(n) +func (a *APIClient) IsValidNamespace(ns string) bool { + ok, err := a.isValidNamespace(ns) if err != nil { - log.Warn().Err(err).Msgf("namespace validation failed for: %q", n) + log.Warn().Err(err).Msgf("namespace validation failed for: %q", ns) } return ok diff --git a/internal/config/data/context.go b/internal/config/data/context.go index 48fbe7c3b0..e4fa1c9506 100644 --- a/internal/config/data/context.go +++ b/internal/config/data/context.go @@ -4,6 +4,7 @@ package data import ( + "os" "sync" "github.com/derailed/k9s/internal/client" @@ -70,6 +71,9 @@ func (c *Context) Validate(conn client.Connection, ks KubeSettings) { c.mx.Lock() defer c.mx.Unlock() + if a := os.Getenv(envPFAddress); a != "" { + c.PortForwardAddress = a + } if c.PortForwardAddress == "" { c.PortForwardAddress = defaultPFAddress() } diff --git a/internal/config/data/ns.go b/internal/config/data/ns.go index 57f9d3e678..819430356b 100644 --- a/internal/config/data/ns.go +++ b/internal/config/data/ns.go @@ -32,6 +32,7 @@ func NewActiveNamespace(n string) *Namespace { if n == client.BlankNamespace { n = client.DefaultNamespace } + return &Namespace{ Active: n, Favorites: []string{client.DefaultNamespace}, diff --git a/internal/config/json/schemas/plugins.json b/internal/config/json/schemas/plugins.json index 5c41eb4883..8ef55509b5 100644 --- a/internal/config/json/schemas/plugins.json +++ b/internal/config/json/schemas/plugins.json @@ -14,6 +14,7 @@ "override": { "type": "boolean" }, "description": { "type": "string" }, "confirm": { "type": "boolean" }, + "dangerous": { "type": "boolean" }, "scopes": { "type": "array", "items": { "type": "string" } diff --git a/internal/config/plugin.go b/internal/config/plugin.go index e57aa53a85..9d45fc14eb 100644 --- a/internal/config/plugin.go +++ b/internal/config/plugin.go @@ -36,6 +36,7 @@ type Plugin struct { Command string `yaml:"command"` Confirm bool `yaml:"confirm"` Background bool `yaml:"background"` + Dangerous bool `yaml:"dangerous"` } func (p Plugin) String() string { diff --git a/internal/dao/pod.go b/internal/dao/pod.go index d65854498b..c836137dd6 100644 --- a/internal/dao/pod.go +++ b/internal/dao/pod.go @@ -207,19 +207,19 @@ func (p *Pod) TailLogs(ctx context.Context, opts *LogOptions) ([]LogChan, error) return append(outs, tailLogs(ctx, p, opts)), nil } for _, co := range po.Spec.InitContainers { - o := opts.Clone() - o.Container = co.Name - outs = append(outs, tailLogs(ctx, p, o)) + cfg := opts.Clone() + cfg.Container = co.Name + outs = append(outs, tailLogs(ctx, p, cfg)) } for _, co := range po.Spec.Containers { - o := opts.Clone() - o.Container = co.Name - outs = append(outs, tailLogs(ctx, p, o)) + cfg := opts.Clone() + cfg.Container = co.Name + outs = append(outs, tailLogs(ctx, p, cfg)) } for _, co := range po.Spec.EphemeralContainers { - o := opts.Clone() - o.Container = co.Name - outs = append(outs, tailLogs(ctx, p, o)) + cfg := opts.Clone() + cfg.Container = co.Name + outs = append(outs, tailLogs(ctx, p, cfg)) } return outs, nil diff --git a/internal/render/sts.go b/internal/render/sts.go index e35560ce04..c83ffa7ba6 100644 --- a/internal/render/sts.go +++ b/internal/render/sts.go @@ -59,16 +59,20 @@ func (s StatefulSet) Render(o interface{}, ns string, r *model1.Row) error { podContainerNames(sts.Spec.Template.Spec, true), podImageNames(sts.Spec.Template.Spec, true), mapToStr(sts.Labels), - AsStatus(s.diagnose(sts.Status.Replicas, sts.Status.ReadyReplicas)), + AsStatus(s.diagnose(sts.Spec.Replicas, sts.Status.Replicas, sts.Status.ReadyReplicas)), ToAge(sts.GetCreationTimestamp()), } return nil } -func (StatefulSet) diagnose(d, r int32) error { +func (StatefulSet) diagnose(w *int32, d, r int32) error { if d != r { - return fmt.Errorf("desiring %d replicas got %d available", d, r) + return fmt.Errorf("desired %d replicas got %d available", d, r) } + if w != nil && *w != r { + return fmt.Errorf("want %d replicas got %d available", *w, r) + } + return nil } diff --git a/internal/view/actions.go b/internal/view/actions.go index 7d76619889..234aa86961 100644 --- a/internal/view/actions.go +++ b/internal/view/actions.go @@ -80,7 +80,7 @@ func hotKeyActions(r Runner, aa *ui.KeyActions) error { errs = errors.Join(errs, fmt.Errorf("duplicate hotkey found for %q in %q", hk.ShortCut, k)) continue } - log.Info().Msgf("Action %q has been overridden by hotkey in %q", hk.ShortCut, k) + log.Debug().Msgf("Action %q has been overridden by hotkey in %q", hk.ShortCut, k) } command, err := r.EnvFn()().Substitute(hk.Command) @@ -110,7 +110,6 @@ func gotoCmd(r Runner, cmd, path string, clearStack bool) ui.ActionHandler { } func pluginActions(r Runner, aa *ui.KeyActions) error { - pp := config.NewPlugins() aa.Range(func(k tcell.Key, a ui.KeyAction) { if a.Opts.Plugin { aa.Delete(k) @@ -121,12 +120,16 @@ func pluginActions(r Runner, aa *ui.KeyActions) error { if err != nil { return err } + pp := config.NewPlugins() if err := pp.Load(path); err != nil { return err } - var errs error - aliases := r.Aliases() + var ( + errs error + aliases = r.Aliases() + ro = r.App().Config.K9s.IsReadOnly() + ) for k, plugin := range pp.Plugins { if !inScope(plugin.Scopes, aliases) { continue @@ -141,15 +144,19 @@ func pluginActions(r Runner, aa *ui.KeyActions) error { errs = errors.Join(errs, fmt.Errorf("duplicate plugin key found for %q in %q", plugin.ShortCut, k)) continue } - log.Info().Msgf("Action %q has been overridden by plugin in %q", plugin.ShortCut, k) + log.Debug().Msgf("Action %q has been overridden by plugin in %q", plugin.ShortCut, k) } + if plugin.Dangerous && ro { + continue + } aa.Add(key, ui.NewKeyActionWithOpts( plugin.Description, pluginAction(r, plugin), ui.ActionOpts{ - Visible: true, - Plugin: true, + Visible: true, + Plugin: true, + Dangerous: plugin.Dangerous, }, )) } diff --git a/internal/view/app.go b/internal/view/app.go index fef223111a..055c95c8a6 100644 --- a/internal/view/app.go +++ b/internal/view/app.go @@ -111,10 +111,6 @@ func (a *App) Init(version string, rate int) error { ns := a.Config.ActiveNamespace() a.factory = watch.NewFactory(a.Conn()) - ok, err := a.isValidNS(ns) - if !ok && err == nil { - return fmt.Errorf("app-init - invalid namespace: %q", ns) - } a.initFactory(ns) a.clusterModel = model.NewClusterInfo(a.factory, a.version, a.Config.K9s) @@ -438,18 +434,6 @@ func (a *App) switchNS(ns string) error { return a.factory.SetActiveNS(ns) } -func (a *App) isValidNS(ns string) (bool, error) { - if ns == client.BlankNamespace || ns == client.NamespaceAll { - return true, nil - } - - if !a.Conn().IsValidNamespace(ns) { - return false, fmt.Errorf("invalid namespace: %q", ns) - } - - return true, nil -} - func (a *App) switchContext(ci *cmd.Interpreter, force bool) error { name, ok := ci.HasContext() if !ok || a.Config.ActiveContextName() == name { @@ -477,12 +461,13 @@ func (a *App) switchContext(ci *cmd.Interpreter, force bool) error { } ns := a.Config.ActiveNamespace() if !a.Conn().IsValidNamespace(ns) { - a.Flash().Errf("Unable to validate namespace %q. Using %q namespace", ns, client.DefaultNamespace) - ns = client.DefaultNamespace + log.Warn().Msgf("Unable to validate namespace: %q. Using %q as active namespace", ns, ns) if err := a.Config.SetActiveNamespace(ns); err != nil { return err } } + a.Flash().Errf("Using %q namespace", ns) + if err := a.Config.Save(true); err != nil { log.Error().Err(err).Msg("config save failed!") } else { diff --git a/internal/view/details.go b/internal/view/details.go index c07c6171b3..235b5d2bcb 100644 --- a/internal/view/details.go +++ b/internal/view/details.go @@ -168,6 +168,7 @@ func (d *Details) StylesChanged(s *config.Styles) { // Update updates the view content. func (d *Details) Update(buff string) *Details { d.model.SetText(buff) + return d } diff --git a/internal/view/dp.go b/internal/view/dp.go index f9cd93d64d..6db577dd07 100644 --- a/internal/view/dp.go +++ b/internal/view/dp.go @@ -53,49 +53,16 @@ func (d *Deploy) logOptions(prev bool) (*dao.LogOptions, error) { if path == "" { return nil, errors.New("you must provide a selection") } - - sts, err := d.dp(path) + dp, err := d.getInstance(path) if err != nil { return nil, err } - cc := sts.Spec.Template.Spec.Containers - var ( - co, dco string - allCos bool - ) - if c, ok := dao.GetDefaultContainer(sts.Spec.Template.ObjectMeta, sts.Spec.Template.Spec); ok { - co, dco = c, c - } else if len(cc) == 1 { - co = cc[0].Name - } else { - dco, allCos = cc[0].Name, true - } - - cfg := d.App().Config.K9s.Logger - opts := dao.LogOptions{ - Path: path, - Container: co, - Lines: int64(cfg.TailCount), - SinceSeconds: cfg.SinceSeconds, - SingleContainer: len(cc) == 1, - AllContainers: allCos, - ShowTimestamp: cfg.ShowTime, - Previous: prev, - } - if co == "" { - opts.AllContainers = true - } - opts.DefaultContainer = dco - - return &opts, nil + return podLogOptions(d.App(), path, prev, dp.ObjectMeta, dp.Spec.Template.Spec), nil } func (d *Deploy) showPods(app *App, model ui.Tabular, gvr client.GVR, fqn string) { - var ddp dao.Deployment - ddp.Init(d.App().factory, d.GVR()) - - dp, err := ddp.GetInstance(fqn) + dp, err := d.getInstance(fqn) if err != nil { app.Flash().Err(err) return @@ -104,7 +71,7 @@ func (d *Deploy) showPods(app *App, model ui.Tabular, gvr client.GVR, fqn string showPodsFromSelector(app, fqn, dp.Spec.Selector) } -func (d *Deploy) dp(fqn string) (*appsv1.Deployment, error) { +func (d *Deploy) getInstance(fqn string) (*appsv1.Deployment, error) { var dp dao.Deployment dp.Init(d.App().factory, d.GVR()) diff --git a/internal/view/ds.go b/internal/view/ds.go index a9e24abd73..6e89f4215b 100644 --- a/internal/view/ds.go +++ b/internal/view/ds.go @@ -4,9 +4,12 @@ package view import ( + "errors" + "github.com/derailed/k9s/internal/client" "github.com/derailed/k9s/internal/dao" "github.com/derailed/k9s/internal/ui" + appsv1 "k8s.io/api/apps/v1" ) // DaemonSet represents a daemon set custom viewer. @@ -16,17 +19,16 @@ type DaemonSet struct { // NewDaemonSet returns a new viewer. func NewDaemonSet(gvr client.GVR) ResourceViewer { - d := DaemonSet{ - ResourceViewer: NewPortForwardExtender( - NewVulnerabilityExtender( - NewRestartExtender( - NewImageExtender( - NewLogsExtender(NewBrowser(gvr), nil), - ), + var d DaemonSet + d.ResourceViewer = NewPortForwardExtender( + NewVulnerabilityExtender( + NewRestartExtender( + NewImageExtender( + NewLogsExtender(NewBrowser(gvr), d.logOptions), ), ), ), - } + ) d.AddBindKeysFn(d.bindKeys) d.GetTable().SetEnterFn(d.showPods) @@ -55,3 +57,23 @@ func (d *DaemonSet) showPods(app *App, model ui.Tabular, _ client.GVR, path stri showPodsFromSelector(app, path, ds.Spec.Selector) } + +func (d *DaemonSet) logOptions(prev bool) (*dao.LogOptions, error) { + path := d.GetTable().GetSelectedItem() + if path == "" { + return nil, errors.New("you must provide a selection") + } + ds, err := d.getInstance(path) + if err != nil { + return nil, err + } + + return podLogOptions(d.App(), path, prev, ds.ObjectMeta, ds.Spec.Template.Spec), nil +} + +func (d *DaemonSet) getInstance(fqn string) (*appsv1.DaemonSet, error) { + var ds dao.DaemonSet + ds.Init(d.App().factory, client.NewGVR("apps/v1/daemonsets")) + + return ds.GetInstance(fqn) +} diff --git a/internal/view/job.go b/internal/view/job.go index 09ff8d6854..e414e3e5c9 100644 --- a/internal/view/job.go +++ b/internal/view/job.go @@ -4,7 +4,10 @@ package view import ( + "errors" + "github.com/derailed/k9s/internal/client" + "github.com/derailed/k9s/internal/dao" "github.com/derailed/k9s/internal/ui" batchv1 "k8s.io/api/batch/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -19,7 +22,11 @@ type Job struct { // NewJob returns a new viewer. func NewJob(gvr client.GVR) ResourceViewer { - j := Job{ResourceViewer: NewVulnerabilityExtender(NewLogsExtender(NewBrowser(gvr), nil))} + var j Job + + j.ResourceViewer = NewVulnerabilityExtender( + NewLogsExtender(NewBrowser(gvr), j.logOptions), + ) j.GetTable().SetEnterFn(j.showPods) j.GetTable().SetSortCol("AGE", true) @@ -42,3 +49,23 @@ func (*Job) showPods(app *App, model ui.Tabular, gvr client.GVR, path string) { showPodsFromSelector(app, path, job.Spec.Selector) } + +func (j *Job) logOptions(prev bool) (*dao.LogOptions, error) { + path := j.GetTable().GetSelectedItem() + if path == "" { + return nil, errors.New("you must provide a selection") + } + job, err := j.getInstance(path) + if err != nil { + return nil, err + } + + return podLogOptions(j.App(), path, prev, job.ObjectMeta, job.Spec.Template.Spec), nil +} + +func (j *Job) getInstance(fqn string) (*batchv1.Job, error) { + var job dao.Job + job.Init(j.App().factory, client.NewGVR("batch/v1/jobs")) + + return job.GetInstance(fqn) +} diff --git a/internal/view/logs_extender.go b/internal/view/logs_extender.go index 95e452117d..d2a8ad4f39 100644 --- a/internal/view/logs_extender.go +++ b/internal/view/logs_extender.go @@ -8,6 +8,8 @@ import ( "github.com/derailed/k9s/internal/dao" "github.com/derailed/k9s/internal/ui" "github.com/derailed/tcell/v2" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // LogsExtender adds log actions to a given viewer. @@ -91,3 +93,27 @@ func (l *LogsExtender) buildLogOpts(path, co string, prevLogs bool) *dao.LogOpti return &opts } + +func podLogOptions(app *App, fqn string, prev bool, m metav1.ObjectMeta, spec v1.PodSpec) *dao.LogOptions { + var ( + cc = fetchContainers(m, spec, true) + cfg = app.Config.K9s.Logger + opts = dao.LogOptions{ + Path: fqn, + Lines: int64(cfg.TailCount), + SinceSeconds: cfg.SinceSeconds, + SingleContainer: len(cc) == 1, + ShowTimestamp: cfg.ShowTime, + Previous: prev, + } + ) + if c, ok := dao.GetDefaultContainer(m, spec); ok { + opts.Container, opts.DefaultContainer = c, c + } else if len(cc) == 1 { + opts.Container = cc[0] + } else { + opts.AllContainers = true + } + + return &opts +} diff --git a/internal/view/pod.go b/internal/view/pod.go index a1971682fc..418029e542 100644 --- a/internal/view/pod.go +++ b/internal/view/pod.go @@ -38,6 +38,7 @@ const ( trDownload = "Download" pfIndicator = "[orange::b]Ⓕ" defaultTxRetries = 999 + magicPrompt = "Yes Please!" ) // Pod represents a pod viewer. @@ -146,24 +147,7 @@ func (p *Pod) logOptions(prev bool) (*dao.LogOptions, error) { return nil, err } - cc, cfg := fetchContainers(pod.ObjectMeta, pod.Spec, true), p.App().Config.K9s.Logger - opts := dao.LogOptions{ - Path: path, - Lines: int64(cfg.TailCount), - SinceSeconds: cfg.SinceSeconds, - SingleContainer: len(cc) == 1, - ShowTimestamp: cfg.ShowTime, - Previous: prev, - } - if c, ok := dao.GetDefaultContainer(pod.ObjectMeta, pod.Spec); ok { - opts.Container, opts.DefaultContainer = c, c - } else if len(cc) == 1 { - opts.Container = cc[0] - } else { - opts.AllContainers = true - } - - return &opts, nil + return podLogOptions(p.App(), path, prev, pod.ObjectMeta, pod.Spec), nil } func (p *Pod) showContainers(app *App, _ ui.Tabular, _ client.GVR, _ string) { @@ -287,9 +271,8 @@ func (p *Pod) sanitizeCmd(evt *tcell.EventKey) *tcell.EventKey { return nil } - ack := "sanitize me pods!" - msg := fmt.Sprintf("Sanitize deletes all pods in completed/error state\nPlease enter [orange::b]%s[-::-] to proceed.", ack) - dialog.ShowConfirmAck(p.App().App, p.App().Content.Pages, ack, true, "Sanitize", msg, func() { + msg := fmt.Sprintf("Sanitize deletes all pods in completed/error state\nPlease enter [orange::b]%s[-::-] to proceed.", magicPrompt) + dialog.ShowConfirmAck(p.App().App, p.App().Content.Pages, magicPrompt, true, "Sanitize", msg, func() { ctx, cancel := context.WithTimeout(context.Background(), 5*p.App().Conn().Config().CallTimeout()) defer cancel() total, err := s.Sanitize(ctx, p.GetTable().GetModel().GetNamespace()) diff --git a/internal/view/sts.go b/internal/view/sts.go index 816dabb984..18636d9a2e 100644 --- a/internal/view/sts.go +++ b/internal/view/sts.go @@ -42,42 +42,12 @@ func (s *StatefulSet) logOptions(prev bool) (*dao.LogOptions, error) { if path == "" { return nil, errors.New("you must provide a selection") } - sts, err := s.getInstance(path) if err != nil { return nil, err } - cc := sts.Spec.Template.Spec.Containers - var ( - co, dco string - allCos bool - ) - if c, ok := dao.GetDefaultContainer(sts.Spec.Template.ObjectMeta, sts.Spec.Template.Spec); ok { - co, dco = c, c - } else if len(cc) == 1 { - co = cc[0].Name - } else { - dco, allCos = cc[0].Name, true - } - - cfg := s.App().Config.K9s.Logger - opts := dao.LogOptions{ - Path: path, - Container: co, - Lines: int64(cfg.TailCount), - SingleContainer: len(cc) == 1, - SinceSeconds: cfg.SinceSeconds, - AllContainers: allCos, - ShowTimestamp: cfg.ShowTime, - Previous: prev, - } - if co == "" { - opts.AllContainers = true - } - opts.DefaultContainer = dco - - return &opts, nil + return podLogOptions(s.App(), path, prev, sts.ObjectMeta, sts.Spec.Template.Spec), nil } func (s *StatefulSet) bindKeys(aa *ui.KeyActions) { @@ -96,5 +66,6 @@ func (s *StatefulSet) showPods(app *App, _ ui.Tabular, _ client.GVR, path string func (s *StatefulSet) getInstance(path string) (*appsv1.StatefulSet, error) { var sts dao.StatefulSet + return sts.GetInstance(s.App().factory, path) } diff --git a/plugins/debug-container.yaml b/plugins/debug-container.yaml index f8561ca29b..aefba8801c 100644 --- a/plugins/debug-container.yaml +++ b/plugins/debug-container.yaml @@ -4,6 +4,7 @@ plugins: debug: shortCut: Shift-D description: Add debug container + dangerous: true scopes: - containers command: bash diff --git a/plugins/helm-purge.yaml b/plugins/helm-purge.yaml index 300053a7fa..c84a8eaa30 100644 --- a/plugins/helm-purge.yaml +++ b/plugins/helm-purge.yaml @@ -4,6 +4,7 @@ plugins: helm-purge: shortCut: Ctrl-P description: Helm Purge + dangerous: true scopes: - po command: kubectl diff --git a/plugins/job-suspend.yaml b/plugins/job-suspend.yaml index abee83bc52..799f884efd 100644 --- a/plugins/job-suspend.yaml +++ b/plugins/job-suspend.yaml @@ -3,6 +3,7 @@ plugins: toggleCronjob: shortCut: Ctrl-S confirm: true + dangerous: true scopes: - cj description: Toggle to suspend or resume a running cronjob diff --git a/plugins/k3d-root-shell.yaml b/plugins/k3d-root-shell.yaml index 79707b4b5a..d44304284c 100644 --- a/plugins/k3d-root-shell.yaml +++ b/plugins/k3d-root-shell.yaml @@ -3,6 +3,7 @@ plugins: k3d-root-shell: shortCut: Shift-S confirm: false + dangerous: true description: "Root Shell" scopes: - containers diff --git a/plugins/liveMigration.yaml b/plugins/liveMigration.yaml index 2ddd08cfc7..a0fbbe72b4 100644 --- a/plugins/liveMigration.yaml +++ b/plugins/liveMigration.yaml @@ -8,7 +8,7 @@ plugins: # Require `virtctl` cli in your PATH, # can be downloaded from Openshift `Command Line Tools` page # or from kubevirt site https://kubevirt.io/user-guide/operations/virtctl_client_tool/ - # + # # liveMigration: # Can be triggered from the VMI (VirtualMachineInstance) view, with shortcut `m` @@ -17,6 +17,7 @@ plugins: description: Live Migrate moves VM to another compute node # Enable confirmation dialog confirm: true + dangerous: true # Collections of views that support this shortcut. (You can use `all`) scopes: - virtualmachineinstance diff --git a/plugins/remove-finalizers.yaml b/plugins/remove-finalizers.yaml index 4abb7d46ac..b7a83d67d5 100644 --- a/plugins/remove-finalizers.yaml +++ b/plugins/remove-finalizers.yaml @@ -11,11 +11,12 @@ plugins: remove_finalizers: shortCut: Ctrl-F confirm: true + dangerous: true scopes: - all description: | Removes all finalizers from selected resource. Be careful when using it, - it may leave dangling resources or delete them + it may leave dangling resources or delete them command: kubectl background: true args: diff --git a/plugins/rm-ns.yaml b/plugins/rm-ns.yaml index 88509dc98c..a73592c040 100644 --- a/plugins/rm-ns.yaml +++ b/plugins/rm-ns.yaml @@ -3,6 +3,7 @@ plugins: rm-ns: shortCut: n confirm: true + dangerous: true description: Remove NS Finalizers scopes: - namespace diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 6fe232a669..233f9c0ac7 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -1,6 +1,6 @@ name: k9s base: core22 -version: 'v0.32.3' +version: 'v0.32.4' 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.