Allow all deletion propagation policies (#1553)

* Allow all deletion propagation policies

* Add "none" deletion propagation policy
mine
Christian Provenzano 2022-05-26 09:48:00 -04:00 committed by GitHub
parent 74d3d6ac23
commit 8e8f874b1e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 55 additions and 31 deletions

View File

@ -10,6 +10,7 @@ import (
"github.com/derailed/k9s/internal" "github.com/derailed/k9s/internal"
"github.com/derailed/k9s/internal/render" "github.com/derailed/k9s/internal/render"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
) )
@ -26,7 +27,7 @@ type Benchmark struct {
} }
// Delete nukes a resource. // Delete nukes a resource.
func (b *Benchmark) Delete(path string, cascade, force bool) error { func (b *Benchmark) Delete(path string, _ *metav1.DeletionPropagation, force bool) error {
return os.Remove(path) return os.Remove(path)
} }

View File

@ -90,7 +90,7 @@ func (g *Generic) ToYAML(path string, showManaged bool) (string, error) {
} }
// Delete deletes a resource. // Delete deletes a resource.
func (g *Generic) Delete(path string, cascade, force bool) error { func (g *Generic) Delete(path string, propagation *metav1.DeletionPropagation, force bool) error {
ns, n := client.Namespaced(path) ns, n := client.Namespaced(path)
auth, err := g.Client().CanI(ns, g.gvr.String(), []string{client.DeleteVerb}) auth, err := g.Client().CanI(ns, g.gvr.String(), []string{client.DeleteVerb})
if err != nil { if err != nil {
@ -100,16 +100,12 @@ func (g *Generic) Delete(path string, cascade, force bool) error {
return fmt.Errorf("user is not authorized to delete %s", path) return fmt.Errorf("user is not authorized to delete %s", path)
} }
p := metav1.DeletePropagationOrphan
if cascade {
p = metav1.DeletePropagationBackground
}
var grace *int64 var grace *int64
if force { if force {
grace = &defaultKillGrace grace = &defaultKillGrace
} }
opts := metav1.DeleteOptions{ opts := metav1.DeleteOptions{
PropagationPolicy: &p, PropagationPolicy: propagation,
GracePeriodSeconds: grace, GracePeriodSeconds: grace,
} }

View File

@ -10,6 +10,7 @@ import (
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
"helm.sh/helm/v3/pkg/action" "helm.sh/helm/v3/pkg/action"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
) )
@ -107,7 +108,7 @@ func (c *Helm) ToYAML(path string, showManaged bool) (string, error) {
} }
// Delete uninstall a Helm. // Delete uninstall a Helm.
func (c *Helm) Delete(path string, cascade, force bool) error { func (c *Helm) Delete(path string, _ *metav1.DeletionPropagation, force bool) error {
ns, n := client.Namespaced(path) ns, n := client.Namespaced(path)
cfg, err := c.EnsureHelmConfig(ns) cfg, err := c.EnsureHelmConfig(ns)
if err != nil { if err != nil {

View File

@ -11,6 +11,7 @@ import (
"github.com/derailed/k9s/internal/config" "github.com/derailed/k9s/internal/config"
"github.com/derailed/k9s/internal/render" "github.com/derailed/k9s/internal/render"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
) )
@ -25,7 +26,7 @@ type PortForward struct {
} }
// Delete a portforward. // Delete a portforward.
func (p *PortForward) Delete(path string, cascade, force bool) error { func (p *PortForward) Delete(path string, _ *metav1.DeletionPropagation, force bool) error {
p.Factory.DeleteForwarder(path) p.Factory.DeleteForwarder(path)
return nil return nil

View File

@ -8,6 +8,7 @@ import (
"github.com/derailed/k9s/internal" "github.com/derailed/k9s/internal"
"github.com/derailed/k9s/internal/render" "github.com/derailed/k9s/internal/render"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
) )
@ -25,7 +26,7 @@ type ScreenDump struct {
} }
// Delete a ScreenDump. // Delete a ScreenDump.
func (d *ScreenDump) Delete(path string, cascade, force bool) error { func (d *ScreenDump) Delete(path string, _ *metav1.DeletionPropagation, force bool) error {
return os.Remove(path) return os.Remove(path)
} }

View File

@ -120,7 +120,7 @@ type Controller interface {
// Nuker represents a resource deleter. // Nuker represents a resource deleter.
type Nuker interface { type Nuker interface {
// Delete removes a resource from the api server. // Delete removes a resource from the api server.
Delete(path string, cascade, force bool) error Delete(path string, propagation *metav1.DeletionPropagation, force bool) error
} }
// Switchable represents a switchable resource. // Switchable represents a switchable resource.

View File

@ -13,6 +13,7 @@ import (
"github.com/derailed/k9s/internal/dao" "github.com/derailed/k9s/internal/dao"
"github.com/derailed/k9s/internal/render" "github.com/derailed/k9s/internal/render"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1" metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
) )
@ -110,7 +111,7 @@ func (t *Table) Get(ctx context.Context, path string) (runtime.Object, error) {
} }
// Delete deletes a resource. // Delete deletes a resource.
func (t *Table) Delete(ctx context.Context, path string, cascade, force bool) error { func (t *Table) Delete(ctx context.Context, path string, propagation *metav1.DeletionPropagation, force bool) error {
meta, err := getMeta(ctx, t.gvr) meta, err := getMeta(ctx, t.gvr)
if err != nil { if err != nil {
return err return err
@ -121,7 +122,7 @@ func (t *Table) Delete(ctx context.Context, path string, cascade, force bool) er
return fmt.Errorf("no nuker for %q", meta.DAO.GVR()) return fmt.Errorf("no nuker for %q", meta.DAO.GVR())
} }
return nuker.Delete(path, cascade, force) return nuker.Delete(path, propagation, force)
} }
// GetNamespace returns the model namespace. // GetNamespace returns the model namespace.

View File

@ -4,18 +4,30 @@ import (
"github.com/derailed/k9s/internal/config" "github.com/derailed/k9s/internal/config"
"github.com/derailed/k9s/internal/ui" "github.com/derailed/k9s/internal/ui"
"github.com/derailed/tview" "github.com/derailed/tview"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
) )
const deleteKey = "delete" const deleteKey = "delete"
const noDeletePropagation = "None"
const defaultPropagationIdx = 0
var propagationOptions []string = []string{
string(metav1.DeletePropagationBackground),
string(metav1.DeletePropagationForeground),
string(metav1.DeletePropagationOrphan),
noDeletePropagation,
}
type ( type (
okFunc func(cascade, force bool) okFunc func(propagation *metav1.DeletionPropagation, force bool)
cancelFunc func() cancelFunc func()
) )
// ShowDelete pops a resource deletion dialog. // ShowDelete pops a resource deletion dialog.
func ShowDelete(styles config.Dialog, pages *ui.Pages, msg string, ok okFunc, cancel cancelFunc) { func ShowDelete(styles config.Dialog, pages *ui.Pages, msg string, ok okFunc, cancel cancelFunc) {
cascade, force := true, false propagation, force := "", false
f := tview.NewForm() f := tview.NewForm()
f.SetItemPadding(0) f.SetItemPadding(0)
f.SetButtonsAlign(tview.AlignCenter). f.SetButtonsAlign(tview.AlignCenter).
@ -23,8 +35,8 @@ func ShowDelete(styles config.Dialog, pages *ui.Pages, msg string, ok okFunc, ca
SetButtonTextColor(styles.ButtonFgColor.Color()). SetButtonTextColor(styles.ButtonFgColor.Color()).
SetLabelColor(styles.LabelFgColor.Color()). SetLabelColor(styles.LabelFgColor.Color()).
SetFieldTextColor(styles.FieldFgColor.Color()) SetFieldTextColor(styles.FieldFgColor.Color())
f.AddCheckbox("Cascade:", cascade, func(_ string, checked bool) { f.AddDropDown("Propagation:", propagationOptions, defaultPropagationIdx, func(_ string, optionIndex int) {
cascade = checked propagation = propagationOptions[optionIndex]
}) })
f.AddCheckbox("Force:", force, func(_ string, checked bool) { f.AddCheckbox("Force:", force, func(_ string, checked bool) {
force = checked force = checked
@ -34,7 +46,13 @@ func ShowDelete(styles config.Dialog, pages *ui.Pages, msg string, ok okFunc, ca
cancel() cancel()
}) })
f.AddButton("OK", func() { f.AddButton("OK", func() {
ok(cascade, force) switch propagation {
case noDeletePropagation:
ok(nil, force)
default:
p := metav1.DeletionPropagation(propagation)
ok(&p, force)
}
dismissDelete(pages) dismissDelete(pages)
cancel() cancel()
}) })

View File

@ -7,13 +7,14 @@ import (
"github.com/derailed/k9s/internal/ui" "github.com/derailed/k9s/internal/ui"
"github.com/derailed/tview" "github.com/derailed/tview"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
) )
func TestDeleteDialog(t *testing.T) { func TestDeleteDialog(t *testing.T) {
p := ui.NewPages() p := ui.NewPages()
okFunc := func(c, f bool) { okFunc := func(p *metav1.DeletionPropagation, f bool) {
assert.True(t, c) assert.Equal(t, propagationOptions[defaultPropagationIdx], p)
assert.True(t, f) assert.True(t, f)
} }
caFunc := func() { caFunc := func() {

View File

@ -12,6 +12,7 @@ import (
"github.com/derailed/k9s/internal/render" "github.com/derailed/k9s/internal/render"
"github.com/derailed/k9s/internal/ui" "github.com/derailed/k9s/internal/ui"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
) )
@ -79,7 +80,7 @@ func (t *mockModel) Get(ctx context.Context, path string) (runtime.Object, error
return nil, nil return nil, nil
} }
func (t *mockModel) Delete(ctx context.Context, path string, c, f bool) error { func (t *mockModel) Delete(ctx context.Context, path string, p *metav1.DeletionPropagation, f bool) error {
return nil return nil
} }

View File

@ -6,6 +6,7 @@ import (
"github.com/derailed/k9s/internal/model" "github.com/derailed/k9s/internal/model"
"github.com/derailed/k9s/internal/render" "github.com/derailed/k9s/internal/render"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
) )
@ -77,5 +78,5 @@ type Tabular interface {
RemoveListener(model.TableListener) RemoveListener(model.TableListener)
// Delete a resource. // Delete a resource.
Delete(ctx context.Context, path string, cascade, force bool) error Delete(ctx context.Context, path string, propagation *metav1.DeletionPropagation, force bool) error
} }

View File

@ -15,6 +15,7 @@ import (
"github.com/gdamore/tcell/v2" "github.com/gdamore/tcell/v2"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
) )
@ -125,7 +126,7 @@ func (t *mockModel) Get(context.Context, string) (runtime.Object, error) {
return nil, nil return nil, nil
} }
func (t *mockModel) Delete(context.Context, string, bool, bool) error { func (t *mockModel) Delete(context.Context, string, *metav1.DeletionPropagation, bool) error {
return nil return nil
} }

View File

@ -523,7 +523,7 @@ func (b *Browser) simpleDelete(selections []string, msg string) {
b.app.Flash().Errf("Invalid nuker %T", b.accessor) b.app.Flash().Errf("Invalid nuker %T", b.accessor)
continue continue
} }
if err := nuker.Delete(sel, true, true); err != nil { if err := nuker.Delete(sel, nil, true); err != nil {
b.app.Flash().Errf("Delete failed with `%s", err) b.app.Flash().Errf("Delete failed with `%s", err)
} else { } else {
b.app.factory.DeleteForwarder(sel) b.app.factory.DeleteForwarder(sel)
@ -535,7 +535,7 @@ func (b *Browser) simpleDelete(selections []string, msg string) {
} }
func (b *Browser) resourceDelete(selections []string, msg string) { func (b *Browser) resourceDelete(selections []string, msg string) {
dialog.ShowDelete(b.app.Styles.Dialog(), b.app.Content.Pages, msg, func(cascade, force bool) { dialog.ShowDelete(b.app.Styles.Dialog(), b.app.Content.Pages, msg, func(propagation *metav1.DeletionPropagation, force bool) {
b.ShowDeleted() b.ShowDeleted()
if len(selections) > 1 { if len(selections) > 1 {
b.app.Flash().Infof("Delete %d marked %s", len(selections), b.GVR()) b.app.Flash().Infof("Delete %d marked %s", len(selections), b.GVR())
@ -543,7 +543,7 @@ func (b *Browser) resourceDelete(selections []string, msg string) {
b.app.Flash().Infof("Delete resource %s %s", b.GVR(), selections[0]) b.app.Flash().Infof("Delete resource %s %s", b.GVR(), selections[0])
} }
for _, sel := range selections { for _, sel := range selections {
if err := b.GetModel().Delete(b.defaultContext(), sel, cascade, force); err != nil { if err := b.GetModel().Delete(b.defaultContext(), sel, propagation, force); err != nil {
b.app.Flash().Errf("Delete failed with `%s", err) b.app.Flash().Errf("Delete failed with `%s", err)
} else { } else {
b.app.factory.DeleteForwarder(sel) b.app.factory.DeleteForwarder(sel)

View File

@ -162,7 +162,7 @@ func (p *PortForward) deleteCmd(evt *tcell.EventKey) *tcell.EventKey {
for _, s := range selections { for _, s := range selections {
var pf dao.PortForward var pf dao.PortForward
pf.Init(p.App().factory, client.NewGVR("portforwards")) pf.Init(p.App().factory, client.NewGVR("portforwards"))
if err := pf.Delete(s, true, true); err != nil { if err := pf.Delete(s, nil, true); err != nil {
p.App().Flash().Err(err) p.App().Flash().Err(err)
return return
} }

View File

@ -177,7 +177,7 @@ func (p *Pod) killCmd(evt *tcell.EventKey) *tcell.EventKey {
} }
p.GetTable().ShowDeleted() p.GetTable().ShowDeleted()
for _, path := range selections { for _, path := range selections {
if err := nuker.Delete(path, true, true); err != nil { if err := nuker.Delete(path, nil, true); err != nil {
p.App().Flash().Errf("Delete failed with %s", err) p.App().Flash().Errf("Delete failed with %s", err)
} else { } else {
p.App().factory.DeleteForwarder(path) p.App().factory.DeleteForwarder(path)

View File

@ -16,6 +16,7 @@ import (
"github.com/derailed/tview" "github.com/derailed/tview"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
) )
@ -110,7 +111,7 @@ func (t *mockTableModel) Get(context.Context, string) (runtime.Object, error) {
return nil, nil return nil, nil
} }
func (t *mockTableModel) Delete(context.Context, string, bool, bool) error { func (t *mockTableModel) Delete(context.Context, string, *metav1.DeletionPropagation, bool) error {
return nil return nil
} }

View File

@ -657,7 +657,7 @@ func (x *Xray) styleTitle() string {
} }
func (x *Xray) resourceDelete(gvr client.GVR, spec *xray.NodeSpec, msg string) { func (x *Xray) resourceDelete(gvr client.GVR, spec *xray.NodeSpec, msg string) {
dialog.ShowDelete(x.app.Styles.Dialog(), x.app.Content.Pages, msg, func(cascade, force bool) { dialog.ShowDelete(x.app.Styles.Dialog(), x.app.Content.Pages, msg, func(propagation *metav1.DeletionPropagation, force bool) {
x.app.Flash().Infof("Delete resource %s %s", spec.GVR(), spec.Path()) x.app.Flash().Infof("Delete resource %s %s", spec.GVR(), spec.Path())
accessor, err := dao.AccessorFor(x.app.factory, gvr) accessor, err := dao.AccessorFor(x.app.factory, gvr)
if err != nil { if err != nil {
@ -670,7 +670,7 @@ func (x *Xray) resourceDelete(gvr client.GVR, spec *xray.NodeSpec, msg string) {
x.app.Flash().Errf("Invalid nuker %T", accessor) x.app.Flash().Errf("Invalid nuker %T", accessor)
return return
} }
if err := nuker.Delete(spec.Path(), true, true); err != nil { if err := nuker.Delete(spec.Path(), nil, true); err != nil {
x.app.Flash().Errf("Delete failed with `%s", err) x.app.Flash().Errf("Delete failed with `%s", err)
} else { } else {
x.app.Flash().Infof("%s `%s deleted successfully", x.GVR(), spec.Path()) x.app.Flash().Infof("%s `%s deleted successfully", x.GVR(), spec.Path())