Release v0.27.3 (#1970)

- [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
mine
Fernand Galiana 2023-02-12 08:12:25 -07:00 committed by GitHub
parent d4ae1c7a74
commit 7c76691c38
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 225 additions and 89 deletions

View File

@ -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}

View File

@ -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) |

View File

@ -0,0 +1,67 @@
<img src="https://raw.githubusercontent.com/derailed/k9s/master/assets/k9s.png" align="center" width="800" height="auto"/>
# 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
---
<img src="https://raw.githubusercontent.com/derailed/k9s/master/assets/imhotep_logo.png" width="32" height="auto"/> © 2022 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)

View File

@ -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()
}

View File

@ -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)
}

View File

@ -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)
}
var gracePeriod *int64
if grace != DefaultGrace {
gracePeriod = (*int64)(&grace)
}
opts := metav1.DeleteOptions{
PropagationPolicy: propagation,
}
if force {
var defaultKillGrace int64 = 1
opts.GracePeriodSeconds = &defaultKillGrace
GracePeriodSeconds: gracePeriod,
}
dial, err := g.dynClient()

View File

@ -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 {

View File

@ -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,
}
}

View File

@ -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

View File

@ -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)
}

View File

@ -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.

View File

@ -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.

View File

@ -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
}

View File

@ -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)
}

View File

@ -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))
}

View File

@ -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("<Delete>", 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)
}

View File

@ -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))
}

View File

@ -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 {

View File

@ -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))
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)

View File

@ -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

View File

@ -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)
}

View File

@ -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{
opts := dao.DrainOptions{
GracePeriodSeconds: -1,
Timeout: 5 * time.Second,
DeleteEmptyDirData: false,
IgnoreAllDaemonSets: false,
}
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.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
}
lines := strings.Split(buff.String(), "\n")
for _, l := range lines {
if len(l) > 0 {
v.App().Flash().Info(l)
}
}
v.Refresh()
}
}
func (n *Node) toggleCordonCmd(cordon bool) func(evt *tcell.EventKey) *tcell.EventKey {

View File

@ -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
}

View File

@ -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)

View File

@ -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
}

View File

@ -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())