diff --git a/Makefile b/Makefile
index cda1763f..3a6c7e0e 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.27.2
+VERSION ?= v0.27.3
IMG_NAME := derailed/k9s
IMAGE := ${IMG_NAME}:${VERSION}
diff --git a/README.md b/README.md
index b632851e..c4fdc8ee 100644
--- a/README.md
+++ b/README.md
@@ -258,7 +258,7 @@ K9s uses aliases to navigate most K8s resources.
| To view and switch to another Kubernetes namespace | `:`ns⏎ | |
| To view all saved resources | `:`screendump or sd⏎ | |
| To delete a resource (TAB and ENTER to confirm) | `ctrl-d` | |
-| To kill a resource (no confirmation dialog!) | `ctrl-k` | |
+| To kill a resource (no confirmation dialog, equivalent to kubectl delete --now) | `ctrl-k` | |
| Launch pulses view | `:`pulses or pu⏎ | |
| Launch XRay view | `:`xray RESOURCE [NAMESPACE]⏎ | RESOURCE can be one of po, svc, dp, rs, sts, ds, NAMESPACE is optional |
| Launch Popeye view | `:`popeye or pop⏎ | See [popeye](#popeye) |
diff --git a/change_logs/release_v0.27.3.md b/change_logs/release_v0.27.3.md
new file mode 100644
index 00000000..7c790f5f
--- /dev/null
+++ b/change_logs/release_v0.27.3.md
@@ -0,0 +1,67 @@
+
+
+# Release v0.27.3
+
+## 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)
+
+---
+
+## ♫ Sounds Behind The Release ♭
+
+* [Bitches Brew - Miles Davis](https://www.youtube.com/watch?v=50fB5L1vmn8)
+* [Sordid Affair - Röyksopp](https://www.youtube.com/watch?v=ECL5zO6ImsA)
+* [Love Inc - Booka Shade](https://www.youtube.com/watch?v=sgLxTcok8kQ)
+* [Twisted - Kaz James,Nick Morgan](https://www.youtube.com/watch?v=oOsYJ-Co8Y4)
+
+---
+
+## A Word From Our Sponsors...
+
+To all the good folks below that opted to `pay it forward` and join our sponsorship program, I salute you!!
+
+* [Astraea](https://github.com/s22)
+* [Arnaud Bienvenu](https://github.com/abienvenu)
+* [Eric Caleb](https://github.com/iamcaleberic)
+* [Sean Williams](https://github.com/SeanThomasWilliams)
+* [Federico Ragona](https://github.com/fedragon)
+
+> Sponsorship cancellations since the last release: `7` ;(
+
+---
+
+## Maintenance Release
+
+---
+
+## Resolved Issues
+
+* [Issue #1968](https://github.com/derailed/k9s/issues/1968) Some skins are missing the definitions for the help menu
+* [Issue #1967](https://github.com/derailed/k9s/issues/1967) Helm cve-2023-25165
+* [Issue #1964](https://github.com/derailed/k9s/issues/1964) logger.sinceSeconds config setting inconsistent with README
+* [Issue #1955](https://github.com/derailed/k9s/issues/1955) K9s crashes with empty resources and/or verbs in RBAC
+* [Issue #1954](https://github.com/derailed/k9s/issues/1954) Open very slow
+* [Issue #1883](https://github.com/derailed/k9s/issues/1883) Fix force deletion
+* [Issue #1788](https://github.com/derailed/k9s/issues/1788) Draining nodes cannot be forced
+* [Issue #1150](https://github.com/derailed/k9s/issues/1150) Add a persistent popup for drain failures
+
+---
+
+## Contributed PRs
+
+Please give `Big Thanks!` and `ATTA Girls/Boys!` to all the fine contributors for making K9s better for all of us!!
+
+* [PR #1969](https://github.com/derailed/k9s/pull/1969) fix: Add missing help menu to gruvbox-dark skin
+* [PR #1966](https://github.com/derailed/k9s/pull/1966) fix: Show meaningful error message when kubectl exec fails
+* [PR #1965](https://github.com/derailed/k9s/pull/1965) set default sinceSeconds to 300
+* [PR #1961](https://github.com/derailed/k9s/pull/1961) feat: Add sort by pod count on node view
+* [PR #1960](https://github.com/derailed/k9s/pull/1960) [Misc] Add Nightfox-theme
+
+---
+
+
© 2022 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
diff --git a/cmd/info.go b/cmd/info.go
index e1f1bbd5..9828aab2 100644
--- a/cmd/info.go
+++ b/cmd/info.go
@@ -3,13 +3,14 @@ package cmd
import (
"fmt"
+ "os"
+
"github.com/derailed/k9s/internal/color"
"github.com/derailed/k9s/internal/config"
"github.com/derailed/k9s/internal/ui"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"gopkg.in/yaml.v2"
- "os"
)
func infoCmd() *cobra.Command {
@@ -56,5 +57,9 @@ func getScreenDumpDirForInfo() string {
log.Error().Err(err).Msgf("Unmarshal k9s config %v", err)
return config.K9sDefaultScreenDumpDir
}
+ if cfg.K9s == nil {
+ cfg.K9s = config.NewK9s()
+ }
+
return cfg.K9s.GetScreenDumpDir()
}
diff --git a/internal/dao/benchmark.go b/internal/dao/benchmark.go
index 35f0bfdc..d0d1afe6 100644
--- a/internal/dao/benchmark.go
+++ b/internal/dao/benchmark.go
@@ -27,7 +27,7 @@ type Benchmark struct {
}
// Delete nukes a resource.
-func (b *Benchmark) Delete(_ context.Context, path string, _ *metav1.DeletionPropagation, force bool) error {
+func (b *Benchmark) Delete(_ context.Context, path string, _ *metav1.DeletionPropagation, _ Grace) error {
return os.Remove(path)
}
diff --git a/internal/dao/generic.go b/internal/dao/generic.go
index 7e8afc8c..22e4eebe 100644
--- a/internal/dao/generic.go
+++ b/internal/dao/generic.go
@@ -12,6 +12,19 @@ import (
"k8s.io/client-go/dynamic"
)
+type Grace int64
+
+const (
+ // DefaultGrace uses delete default termination policy.
+ DefaultGrace Grace = -1
+
+ // ForceGrace sets delete grace-period to 0.
+ ForceGrace Grace = 0
+
+ // NowGrace set delete grace-period to 1,
+ NowGrace Grace = 1
+)
+
var _ Describer = (*Generic)(nil)
// Generic represents a generic resource.
@@ -88,7 +101,7 @@ func (g *Generic) ToYAML(path string, showManaged bool) (string, error) {
}
// Delete deletes a resource.
-func (g *Generic) Delete(ctx context.Context, path string, propagation *metav1.DeletionPropagation, force bool) error {
+func (g *Generic) Delete(ctx context.Context, path string, propagation *metav1.DeletionPropagation, grace Grace) error {
ns, n := client.Namespaced(path)
auth, err := g.Client().CanI(ns, g.gvr.String(), []string{client.DeleteVerb})
if err != nil {
@@ -98,13 +111,13 @@ func (g *Generic) Delete(ctx context.Context, path string, propagation *metav1.D
return fmt.Errorf("user is not authorized to delete %s", path)
}
- opts := metav1.DeleteOptions{
- PropagationPolicy: propagation,
+ var gracePeriod *int64
+ if grace != DefaultGrace {
+ gracePeriod = (*int64)(&grace)
}
-
- if force {
- var defaultKillGrace int64 = 1
- opts.GracePeriodSeconds = &defaultKillGrace
+ opts := metav1.DeleteOptions{
+ PropagationPolicy: propagation,
+ GracePeriodSeconds: gracePeriod,
}
dial, err := g.dynClient()
diff --git a/internal/dao/helm.go b/internal/dao/helm.go
index 322d2aa0..0c4ffd48 100644
--- a/internal/dao/helm.go
+++ b/internal/dao/helm.go
@@ -111,7 +111,7 @@ func (h *Helm) ToYAML(path string, showManaged bool) (string, error) {
}
// Delete uninstall a Helm.
-func (h *Helm) Delete(_ context.Context, path string, _ *metav1.DeletionPropagation, force bool) error {
+func (h *Helm) Delete(_ context.Context, path string, _ *metav1.DeletionPropagation, _ Grace) error {
ns, n := client.Namespaced(path)
cfg, err := h.EnsureHelmConfig(ns)
if err != nil {
diff --git a/internal/dao/node.go b/internal/dao/node.go
index 8686d0c0..09540d86 100644
--- a/internal/dao/node.go
+++ b/internal/dao/node.go
@@ -77,6 +77,7 @@ func (o DrainOptions) toDrainHelper(k kubernetes.Interface, w io.Writer) drain.H
IgnoreAllDaemonSets: o.IgnoreAllDaemonSets,
Out: w,
ErrOut: w,
+ Force: o.Force,
}
}
diff --git a/internal/dao/port_forward.go b/internal/dao/port_forward.go
index c4f05837..8e7e4c54 100644
--- a/internal/dao/port_forward.go
+++ b/internal/dao/port_forward.go
@@ -26,7 +26,7 @@ type PortForward struct {
}
// Delete deletes a portforward.
-func (p *PortForward) Delete(_ context.Context, path string, _ *metav1.DeletionPropagation, _ bool) error {
+func (p *PortForward) Delete(_ context.Context, path string, _ *metav1.DeletionPropagation, _ Grace) error {
p.GetFactory().DeleteForwarder(path)
return nil
diff --git a/internal/dao/screen_dump.go b/internal/dao/screen_dump.go
index c1c60925..7ca99626 100644
--- a/internal/dao/screen_dump.go
+++ b/internal/dao/screen_dump.go
@@ -22,7 +22,7 @@ type ScreenDump struct {
}
// Delete a ScreenDump.
-func (d *ScreenDump) Delete(_ context.Context, path string, _ *metav1.DeletionPropagation, force bool) error {
+func (d *ScreenDump) Delete(_ context.Context, path string, _ *metav1.DeletionPropagation, _ Grace) error {
return os.Remove(path)
}
diff --git a/internal/dao/types.go b/internal/dao/types.go
index e2650f41..aa1f49e2 100644
--- a/internal/dao/types.go
+++ b/internal/dao/types.go
@@ -120,7 +120,7 @@ type Controller interface {
// Nuker represents a resource deleter.
type Nuker interface {
// Delete removes a resource from the api server.
- Delete(ctx context.Context, path string, propagation *metav1.DeletionPropagation, force bool) error
+ Delete(context.Context, string, *metav1.DeletionPropagation, Grace) error
}
// Switchable represents a switchable resource.
diff --git a/internal/model/table.go b/internal/model/table.go
index 799c385d..861fd1eb 100644
--- a/internal/model/table.go
+++ b/internal/model/table.go
@@ -111,7 +111,7 @@ func (t *Table) Get(ctx context.Context, path string) (runtime.Object, error) {
}
// Delete deletes a resource.
-func (t *Table) Delete(ctx context.Context, path string, propagation *metav1.DeletionPropagation, force bool) error {
+func (t *Table) Delete(ctx context.Context, path string, propagation *metav1.DeletionPropagation, grace dao.Grace) error {
meta, err := getMeta(ctx, t.gvr)
if err != nil {
return err
@@ -122,7 +122,7 @@ func (t *Table) Delete(ctx context.Context, path string, propagation *metav1.Del
return fmt.Errorf("no nuker for %q", meta.DAO.GVR())
}
- return nuker.Delete(ctx, path, propagation, force)
+ return nuker.Delete(ctx, path, propagation, grace)
}
// GetNamespace returns the model namespace.
diff --git a/internal/render/policy.go b/internal/render/policy.go
index 36709250..9f3ff919 100644
--- a/internal/render/policy.go
+++ b/internal/render/policy.go
@@ -74,6 +74,9 @@ func (Policy) Render(o interface{}, gvr string, r *Row) error {
// Helpers...
func cleanseResource(r string) string {
+ if r == "" {
+ return r
+ }
if r[0] == '/' {
return r
}
diff --git a/internal/ui/dialog/confirm.go b/internal/ui/dialog/confirm.go
index e1e88d77..e7278e34 100644
--- a/internal/ui/dialog/confirm.go
+++ b/internal/ui/dialog/confirm.go
@@ -6,11 +6,9 @@ import (
"github.com/derailed/tview"
)
-const confirmKey = "confirm"
+const dialogKey = "dialog"
-type (
- confirmFunc func()
-)
+type confirmFunc func()
// ShowConfirm pops a confirmation dialog.
func ShowConfirm(styles config.Dialog, pages *ui.Pages, title, msg string, ack confirmFunc, cancel cancelFunc) {
@@ -22,12 +20,12 @@ func ShowConfirm(styles config.Dialog, pages *ui.Pages, title, msg string, ack c
SetLabelColor(styles.LabelFgColor.Color()).
SetFieldTextColor(styles.FieldFgColor.Color())
f.AddButton("Cancel", func() {
- dismissConfirm(pages)
+ dismiss(pages)
cancel()
})
f.AddButton("OK", func() {
ack()
- dismissConfirm(pages)
+ dismiss(pages)
cancel()
})
for i := 0; i < 2; i++ {
@@ -43,13 +41,13 @@ func ShowConfirm(styles config.Dialog, pages *ui.Pages, title, msg string, ack c
modal.SetText(msg)
modal.SetTextColor(styles.FgColor.Color())
modal.SetDoneFunc(func(int, string) {
- dismissConfirm(pages)
+ dismiss(pages)
cancel()
})
- pages.AddPage(confirmKey, modal, false, false)
- pages.ShowPage(confirmKey)
+ pages.AddPage(dialogKey, modal, false, false)
+ pages.ShowPage(dialogKey)
}
-func dismissConfirm(pages *ui.Pages) {
- pages.RemovePage(confirmKey)
+func dismiss(pages *ui.Pages) {
+ pages.RemovePage(dialogKey)
}
diff --git a/internal/ui/dialog/confirm_test.go b/internal/ui/dialog/confirm_test.go
index bda10a9d..f5cd1429 100644
--- a/internal/ui/dialog/confirm_test.go
+++ b/internal/ui/dialog/confirm_test.go
@@ -22,9 +22,9 @@ func TestConfirmDialog(t *testing.T) {
}
ShowConfirm(config.Dialog{}, p, "Blee", "Yo", ackFunc, caFunc)
- d := p.GetPrimitive(confirmKey).(*tview.ModalForm)
+ d := p.GetPrimitive(dialogKey).(*tview.ModalForm)
assert.NotNil(t, d)
- dismissConfirm(p)
- assert.Nil(t, p.GetPrimitive(confirmKey))
+ dismiss(p)
+ assert.Nil(t, p.GetPrimitive(dialogKey))
}
diff --git a/internal/ui/dialog/delete.go b/internal/ui/dialog/delete.go
index 0f8357c8..bd1bb675 100644
--- a/internal/ui/dialog/delete.go
+++ b/internal/ui/dialog/delete.go
@@ -7,11 +7,15 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
-const deleteKey = "delete"
+const (
+ noDeletePropagation = "None"
+ defaultPropagationIdx = 0
+)
-const noDeletePropagation = "None"
-
-const defaultPropagationIdx = 0
+type (
+ okFunc func(propagation *metav1.DeletionPropagation, force bool)
+ cancelFunc func()
+)
var propagationOptions []string = []string{
string(metav1.DeletePropagationBackground),
@@ -20,11 +24,6 @@ var propagationOptions []string = []string{
noDeletePropagation,
}
-type (
- okFunc func(propagation *metav1.DeletionPropagation, force bool)
- cancelFunc func()
-)
-
// ShowDelete pops a resource deletion dialog.
func ShowDelete(styles config.Dialog, pages *ui.Pages, msg string, ok okFunc, cancel cancelFunc) {
propagation, force := "", false
@@ -47,7 +46,7 @@ func ShowDelete(styles config.Dialog, pages *ui.Pages, msg string, ok okFunc, ca
force = checked
})
f.AddButton("Cancel", func() {
- dismissDelete(pages)
+ dismiss(pages)
cancel()
})
f.AddButton("OK", func() {
@@ -58,7 +57,7 @@ func ShowDelete(styles config.Dialog, pages *ui.Pages, msg string, ok okFunc, ca
p := metav1.DeletionPropagation(propagation)
ok(&p, force)
}
- dismissDelete(pages)
+ dismiss(pages)
cancel()
})
for i := 0; i < 2; i++ {
@@ -74,13 +73,9 @@ func ShowDelete(styles config.Dialog, pages *ui.Pages, msg string, ok okFunc, ca
confirm := tview.NewModalForm("", f)
confirm.SetText(msg)
confirm.SetDoneFunc(func(int, string) {
- dismissDelete(pages)
+ dismiss(pages)
cancel()
})
- pages.AddPage(deleteKey, confirm, false, false)
- pages.ShowPage(deleteKey)
-}
-
-func dismissDelete(pages *ui.Pages) {
- pages.RemovePage(deleteKey)
+ pages.AddPage(dialogKey, confirm, false, false)
+ pages.ShowPage(dialogKey)
}
diff --git a/internal/ui/dialog/delete_test.go b/internal/ui/dialog/delete_test.go
index a81cdb00..a4c14166 100644
--- a/internal/ui/dialog/delete_test.go
+++ b/internal/ui/dialog/delete_test.go
@@ -22,9 +22,9 @@ func TestDeleteDialog(t *testing.T) {
}
ShowDelete(config.Dialog{}, p, "Yo", okFunc, caFunc)
- d := p.GetPrimitive(deleteKey).(*tview.ModalForm)
+ d := p.GetPrimitive(dialogKey).(*tview.ModalForm)
assert.NotNil(t, d)
- dismissDelete(p)
- assert.Nil(t, p.GetPrimitive(deleteKey))
+ dismiss(p)
+ assert.Nil(t, p.GetPrimitive(dialogKey))
}
diff --git a/internal/ui/dialog/error.go b/internal/ui/dialog/error.go
index b17a29aa..f39e31fd 100644
--- a/internal/ui/dialog/error.go
+++ b/internal/ui/dialog/error.go
@@ -10,7 +10,7 @@ import (
"github.com/derailed/tview"
)
-// ShowConfirm pops a confirmation dialog.
+// ShowError pops an error dialog.
func ShowError(styles config.Dialog, pages *ui.Pages, msg string) {
f := tview.NewForm()
f.SetItemPadding(0)
@@ -20,7 +20,7 @@ func ShowError(styles config.Dialog, pages *ui.Pages, msg string) {
SetLabelColor(styles.LabelFgColor.Color()).
SetFieldTextColor(tcell.ColorIndianRed)
f.AddButton("Dismiss", func() {
- dismissError(pages)
+ dismiss(pages)
})
if b := f.GetButton(0); b != nil {
b.SetBackgroundColorActivated(styles.ButtonFocusBgColor.Color())
@@ -31,14 +31,10 @@ func ShowError(styles config.Dialog, pages *ui.Pages, msg string) {
modal.SetText(cowTalk(msg))
modal.SetTextColor(tcell.ColorOrangeRed)
modal.SetDoneFunc(func(int, string) {
- dismissError(pages)
+ dismiss(pages)
})
- pages.AddPage(confirmKey, modal, false, false)
- pages.ShowPage(confirmKey)
-}
-
-func dismissError(pages *ui.Pages) {
- pages.RemovePage(confirmKey)
+ pages.AddPage(dialogKey, modal, false, false)
+ pages.ShowPage(dialogKey)
}
func cowTalk(says string) string {
diff --git a/internal/ui/dialog/error_test.go b/internal/ui/dialog/error_test.go
new file mode 100644
index 00000000..f882ac68
--- /dev/null
+++ b/internal/ui/dialog/error_test.go
@@ -0,0 +1,21 @@
+package dialog
+
+import (
+ "testing"
+
+ "github.com/derailed/k9s/internal/config"
+ "github.com/derailed/k9s/internal/ui"
+ "github.com/derailed/tview"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestErrorDialog(t *testing.T) {
+ p := ui.NewPages()
+
+ ShowError(config.Dialog{}, p, "Yo")
+
+ d := p.GetPrimitive(dialogKey).(*tview.ModalForm)
+ assert.NotNil(t, d)
+ dismiss(p)
+ assert.Nil(t, p.GetPrimitive(dialogKey))
+}
diff --git a/internal/ui/table_test.go b/internal/ui/table_test.go
index 0ba5e161..6567bb9a 100644
--- a/internal/ui/table_test.go
+++ b/internal/ui/table_test.go
@@ -8,6 +8,7 @@ import (
"github.com/derailed/k9s/internal"
"github.com/derailed/k9s/internal/client"
"github.com/derailed/k9s/internal/config"
+ "github.com/derailed/k9s/internal/dao"
"github.com/derailed/k9s/internal/model"
"github.com/derailed/k9s/internal/render"
"github.com/derailed/k9s/internal/ui"
@@ -80,7 +81,7 @@ func (t *mockModel) Get(ctx context.Context, path string) (runtime.Object, error
return nil, nil
}
-func (t *mockModel) Delete(ctx context.Context, path string, p *metav1.DeletionPropagation, f bool) error {
+func (t *mockModel) Delete(context.Context, string, *metav1.DeletionPropagation, dao.Grace) error {
return nil
}
diff --git a/internal/ui/types.go b/internal/ui/types.go
index c8f747ef..297f22b4 100644
--- a/internal/ui/types.go
+++ b/internal/ui/types.go
@@ -4,6 +4,7 @@ import (
"context"
"time"
+ "github.com/derailed/k9s/internal/dao"
"github.com/derailed/k9s/internal/model"
"github.com/derailed/k9s/internal/render"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -78,5 +79,5 @@ type Tabular interface {
RemoveListener(model.TableListener)
// Delete a resource.
- Delete(ctx context.Context, path string, propagation *metav1.DeletionPropagation, force bool) error
+ Delete(context.Context, string, *metav1.DeletionPropagation, dao.Grace) error
}
diff --git a/internal/view/alias_test.go b/internal/view/alias_test.go
index 9b86d9bb..00f91684 100644
--- a/internal/view/alias_test.go
+++ b/internal/view/alias_test.go
@@ -8,6 +8,7 @@ import (
"github.com/derailed/k9s/internal"
"github.com/derailed/k9s/internal/client"
"github.com/derailed/k9s/internal/config"
+ "github.com/derailed/k9s/internal/dao"
"github.com/derailed/k9s/internal/model"
"github.com/derailed/k9s/internal/render"
"github.com/derailed/k9s/internal/ui"
@@ -126,7 +127,7 @@ func (t *mockModel) Get(context.Context, string) (runtime.Object, error) {
return nil, nil
}
-func (t *mockModel) Delete(context.Context, string, *metav1.DeletionPropagation, bool) error {
+func (t *mockModel) Delete(context.Context, string, *metav1.DeletionPropagation, dao.Grace) error {
return nil
}
diff --git a/internal/view/browser.go b/internal/view/browser.go
index b4cdc548..3d833dd8 100644
--- a/internal/view/browser.go
+++ b/internal/view/browser.go
@@ -121,6 +121,7 @@ func (b *Browser) bindKeys(aa ui.KeyActions) {
tcell.KeyEscape: ui.NewSharedKeyAction("Filter Reset", b.resetCmd, false),
tcell.KeyEnter: ui.NewSharedKeyAction("Filter", b.filterCmd, false),
tcell.KeyHelp: ui.NewSharedKeyAction("Help", b.helpCmd, false),
+ ui.KeyV: ui.NewSharedKeyAction("Zob", b.blahCmd, true),
})
}
@@ -350,6 +351,28 @@ func (b *Browser) deleteCmd(evt *tcell.EventKey) *tcell.EventKey {
return nil
}
+func (b *Browser) blahCmd(evt *tcell.EventKey) *tcell.EventKey {
+ b.Stop()
+ defer b.Start()
+ {
+ v := NewDetails(b.app, "Results", "Blee", true)
+ if err := v.app.inject(v, false); err != nil {
+ v.app.Flash().Err(err)
+ }
+
+ for i := 0; i < 10; i++ {
+ j := i
+ b.app.QueueUpdateDraw(func() {
+ log.Debug().Msgf("YO %d", j)
+ fmt.Fprintf(v.GetWriter(), "Yo %d\n", j)
+ time.Sleep(1 * time.Second)
+ })
+ }
+ }
+
+ return nil
+}
+
func (b *Browser) describeCmd(evt *tcell.EventKey) *tcell.EventKey {
path := b.GetSelectedItem()
if path == "" {
@@ -531,7 +554,7 @@ func (b *Browser) simpleDelete(selections []string, msg string) {
b.app.Flash().Errf("Invalid nuker %T", b.accessor)
continue
}
- if err := nuker.Delete(context.Background(), sel, nil, false); err != nil {
+ if err := nuker.Delete(context.Background(), sel, nil, dao.DefaultGrace); err != nil {
b.app.Flash().Errf("Delete failed with `%s", err)
} else {
b.app.factory.DeleteForwarder(sel)
@@ -551,7 +574,11 @@ func (b *Browser) resourceDelete(selections []string, msg string) {
b.app.Flash().Infof("Delete resource %s %s", b.GVR(), selections[0])
}
for _, sel := range selections {
- if err := b.GetModel().Delete(b.defaultContext(), sel, propagation, force); err != nil {
+ grace := dao.DefaultGrace
+ if force {
+ grace = dao.ForceGrace
+ }
+ if err := b.GetModel().Delete(b.defaultContext(), sel, propagation, grace); err != nil {
b.app.Flash().Errf("Delete failed with `%s", err)
} else {
b.app.factory.DeleteForwarder(sel)
diff --git a/internal/view/details.go b/internal/view/details.go
index 066b0558..d65485a2 100644
--- a/internal/view/details.go
+++ b/internal/view/details.go
@@ -3,6 +3,7 @@ package view
import (
"context"
"fmt"
+ "io"
"strings"
"github.com/derailed/k9s/internal/config"
@@ -159,6 +160,10 @@ func (d *Details) Update(buff string) *Details {
return d
}
+func (d *Details) GetWriter() io.Writer {
+ return d.text
+}
+
// SetSubject updates the subject.
func (d *Details) SetSubject(s string) {
d.subject = s
diff --git a/internal/view/help.go b/internal/view/help.go
index bd04ebcb..d9ce5085 100644
--- a/internal/view/help.go
+++ b/internal/view/help.go
@@ -281,7 +281,6 @@ func (h *Help) resetTitle() {
func (h *Help) addSpacer(c int) {
cell := tview.NewTableCell(render.Pad("", h.maxKey))
- cell.SetBackgroundColor(h.App().Styles.BgColor())
cell.SetExpansion(1)
h.SetCell(0, c, cell)
}
diff --git a/internal/view/node.go b/internal/view/node.go
index a025de51..9cce2783 100644
--- a/internal/view/node.go
+++ b/internal/view/node.go
@@ -1,10 +1,8 @@
package view
import (
- "bytes"
"context"
"fmt"
- "strings"
"time"
"github.com/derailed/k9s/internal/client"
@@ -71,13 +69,11 @@ func (n *Node) drainCmd(evt *tcell.EventKey) *tcell.EventKey {
return evt
}
- defaults := dao.DrainOptions{
- GracePeriodSeconds: -1,
- Timeout: 5 * time.Second,
- DeleteEmptyDirData: false,
- IgnoreAllDaemonSets: false,
+ opts := dao.DrainOptions{
+ GracePeriodSeconds: -1,
+ Timeout: 5 * time.Second,
}
- ShowDrain(n, path, defaults, drainNode)
+ ShowDrain(n, path, opts, drainNode)
return nil
}
@@ -94,18 +90,20 @@ func drainNode(v ResourceViewer, path string, opts dao.DrainOptions) {
return
}
- buff := bytes.NewBufferString("")
- if err := m.Drain(path, opts, buff); err != nil {
- v.App().Flash().Err(err)
- return
- }
- lines := strings.Split(buff.String(), "\n")
- for _, l := range lines {
- if len(l) > 0 {
- v.App().Flash().Info(l)
+ v.Stop()
+ defer v.Start()
+ {
+ d := NewDetails(v.App(), "Drain Progress", path, true)
+ if err := v.App().inject(d, false); err != nil {
+ v.App().Flash().Err(err)
}
+
+ if err := m.Drain(path, opts, d.GetWriter()); err != nil {
+ v.App().Flash().Err(err)
+ return
+ }
+ v.Refresh()
}
- v.Refresh()
}
func (n *Node) toggleCordonCmd(cordon bool) func(evt *tcell.EventKey) *tcell.EventKey {
diff --git a/internal/view/pf.go b/internal/view/pf.go
index 85b452c0..0d268089 100644
--- a/internal/view/pf.go
+++ b/internal/view/pf.go
@@ -160,7 +160,7 @@ func (p *PortForward) deleteCmd(evt *tcell.EventKey) *tcell.EventKey {
for _, s := range selections {
var pf dao.PortForward
pf.Init(p.App().factory, client.NewGVR("portforwards"))
- if err := pf.Delete(context.Background(), s, nil, true); err != nil {
+ if err := pf.Delete(context.Background(), s, nil, dao.DefaultGrace); err != nil {
p.App().Flash().Err(err)
return
}
diff --git a/internal/view/pod.go b/internal/view/pod.go
index 58aa6667..531f16d8 100644
--- a/internal/view/pod.go
+++ b/internal/view/pod.go
@@ -200,7 +200,7 @@ func (p *Pod) killCmd(evt *tcell.EventKey) *tcell.EventKey {
}
p.GetTable().ShowDeleted()
for _, path := range selections {
- if err := nuker.Delete(context.Background(), path, nil, true); err != nil {
+ if err := nuker.Delete(context.Background(), path, nil, dao.NowGrace); err != nil {
p.App().Flash().Errf("Delete failed with %s", err)
} else {
p.App().factory.DeleteForwarder(path)
diff --git a/internal/view/table_int_test.go b/internal/view/table_int_test.go
index 6eb7b9b6..cebdc3f5 100644
--- a/internal/view/table_int_test.go
+++ b/internal/view/table_int_test.go
@@ -10,6 +10,7 @@ import (
"github.com/derailed/k9s/internal"
"github.com/derailed/k9s/internal/client"
"github.com/derailed/k9s/internal/config"
+ "github.com/derailed/k9s/internal/dao"
"github.com/derailed/k9s/internal/model"
"github.com/derailed/k9s/internal/render"
"github.com/derailed/k9s/internal/ui"
@@ -140,7 +141,7 @@ func (t *mockTableModel) Get(context.Context, string) (runtime.Object, error) {
return nil, nil
}
-func (t *mockTableModel) Delete(context.Context, string, *metav1.DeletionPropagation, bool) error {
+func (t *mockTableModel) Delete(context.Context, string, *metav1.DeletionPropagation, dao.Grace) error {
return nil
}
diff --git a/internal/view/xray.go b/internal/view/xray.go
index ea86e377..87a05b38 100644
--- a/internal/view/xray.go
+++ b/internal/view/xray.go
@@ -672,7 +672,11 @@ func (x *Xray) resourceDelete(gvr client.GVR, spec *xray.NodeSpec, msg string) {
x.app.Flash().Errf("Invalid nuker %T", accessor)
return
}
- if err := nuker.Delete(context.Background(), spec.Path(), nil, true); err != nil {
+ grace := dao.DefaultGrace
+ if force {
+ grace = dao.ForceGrace
+ }
+ if err := nuker.Delete(context.Background(), spec.Path(), nil, grace); err != nil {
x.app.Flash().Errf("Delete failed with `%s", err)
} else {
x.app.Flash().Infof("%s `%s deleted successfully", x.GVR(), spec.Path())