Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 25 additions & 6 deletions commands/live/destroy/cmddestroy.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2021 The kpt Authors
// Copyright 2021,2026 The kpt Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -18,13 +18,15 @@ import (
"context"
"fmt"
"os"
"time"

"github.com/kptdev/kpt/internal/docs/generated/livedocs"
argsutil "github.com/kptdev/kpt/pkg/lib/util/args"
"github.com/kptdev/kpt/pkg/lib/util/strings"
"github.com/kptdev/kpt/pkg/live"
"github.com/kptdev/kpt/pkg/status"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/kubectl/pkg/cmd/util"
"sigs.k8s.io/cli-utils/cmd/flagutils"
Expand Down Expand Up @@ -67,6 +69,12 @@ func NewRunner(
c.Flags().StringVar(&r.statusPolicyString, "status-policy", "all",
"It determines which status information should be saved in the inventory (if compatible). Available options "+
fmt.Sprintf("%q and %q.", "all", "none"))
c.Flags().StringVar(&r.deletePropagationPolicyString, "delete-propagation-policy",
"Background", "The propagation policy that should be used when deleting resources. "+
"The available options are 'Background', 'Foreground', and 'Orphan'.")
c.Flags().DurationVar(&r.deleteTimeout, "delete-timeout", time.Duration(0),
"Timeout threshold for waiting for all resources to be deleted. "+
"If not set, kpt will wait until interrupted.")
return r
}

Expand All @@ -91,8 +99,12 @@ type Runner struct {
printStatusEvents bool
statusPolicyString string

inventoryPolicy inventory.Policy
statusPolicy inventory.StatusPolicy
deletePropagationPolicyString string
deleteTimeout time.Duration

inventoryPolicy inventory.Policy
statusPolicy inventory.StatusPolicy
deletePropPolicy metav1.DeletionPropagation

// TODO(mortent): This is needed for now since we don't have a good way to
// stub out the Destroyer with an interface for testing purposes.
Expand All @@ -111,6 +123,11 @@ func (r *Runner) preRunE(_ *cobra.Command, _ []string) error {
return err
}

r.deletePropPolicy, err = flagutils.ConvertPropagationPolicy(r.deletePropagationPolicyString)
if err != nil {
return fmt.Errorf("delete propagation policy must be one of Background, Foreground, Orphan")
}

if found := printers.ValidatePrinterType(r.output); !found {
return fmt.Errorf("unknown output type %q", r.output)
}
Expand Down Expand Up @@ -188,9 +205,11 @@ func runDestroy(r *Runner, inv inventory.Info, dryRunStrategy common.DryRunStrat
}

options := apply.DestroyerOptions{
InventoryPolicy: r.inventoryPolicy,
DryRunStrategy: dryRunStrategy,
EmitStatusEvents: true,
InventoryPolicy: r.inventoryPolicy,
DryRunStrategy: dryRunStrategy,
DeletePropagationPolicy: r.deletePropPolicy,
DeleteTimeout: r.deleteTimeout,
EmitStatusEvents: true,
}
ch := destroyer.Run(r.ctx, inv, options)

Expand Down
85 changes: 55 additions & 30 deletions commands/live/destroy/cmddestroy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,68 +17,92 @@ package destroy
import (
"path/filepath"
"testing"
"time"

kptfilev1 "github.com/kptdev/kpt/api/kptfile/v1"
"github.com/kptdev/kpt/internal/testutil"
"github.com/kptdev/kpt/pkg/kptfile/kptfileutil"
"github.com/kptdev/kpt/pkg/printer/fake"
"github.com/stretchr/testify/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/cli-runtime/pkg/genericclioptions"
cmdtesting "k8s.io/kubectl/pkg/cmd/testing"
"sigs.k8s.io/cli-utils/pkg/common"
"sigs.k8s.io/cli-utils/pkg/inventory"
)

func TestCmd(t *testing.T) {
validInventory := &kptfilev1.Inventory{
Namespace: "my-ns",
Name: "my-name",
InventoryID: "my-inv-id",
}

// failOnDestroy is used for error cases where preRunE should reject the
// input before the destroy runner is reached.
failOnDestroy := func(t *testing.T, _ *Runner, _ inventory.Info) {
t.Fatal("destroy runner should not be called for error cases")
}

testCases := map[string]struct {
args []string
namespace string
inventory *kptfilev1.Inventory
destroyCallbackFunc func(*testing.T, inventory.Info)
destroyCallbackFunc func(*testing.T, *Runner, inventory.Info)
expectedErrorMsg string
}{
"invalid inventory policy": {
args: []string{
"--inventory-policy", "noSuchPolicy",
},
namespace: "testns",
destroyCallbackFunc: func(t *testing.T, _ inventory.Info) {
t.FailNow()
},
expectedErrorMsg: "inventory policy must be one of strict, adopt",
"destroy rejects invalid inventory policy": {
args: []string{"--inventory-policy", "noSuchPolicy"},
namespace: "testns",
destroyCallbackFunc: failOnDestroy,
expectedErrorMsg: "inventory policy must be one of strict, adopt",
},
"destroy rejects invalid status policy": {
args: []string{"--status-policy", "noSuchPolicy"},
namespace: "testns",
destroyCallbackFunc: failOnDestroy,
expectedErrorMsg: "status policy must be one of none, all",
},
"invalid status policy": {
"destroy rejects invalid output format": {
args: []string{"--output", "foo"},
namespace: "testns",
destroyCallbackFunc: failOnDestroy,
expectedErrorMsg: "unknown output type \"foo\"",
},
"destroy rejects invalid delete-propagation-policy": {
args: []string{"--delete-propagation-policy", "noSuchPolicy"},
namespace: "testns",
destroyCallbackFunc: failOnDestroy,
expectedErrorMsg: "delete propagation policy must be one of Background, Foreground, Orphan",
},
"destroy accepts Foreground delete-propagation-policy": {
args: []string{
"--status-policy", "noSuchPolicy",
"--delete-propagation-policy", "Foreground",
},
inventory: validInventory,
namespace: "testns",
destroyCallbackFunc: func(t *testing.T, _ inventory.Info) {
t.FailNow()
destroyCallbackFunc: func(t *testing.T, r *Runner, _ inventory.Info) {
assert.Equal(t, metav1.DeletePropagationForeground, r.deletePropPolicy)
},
expectedErrorMsg: "status policy must be one of none, all",
},
"invalid output format": {
"destroy parses delete-timeout duration": {
args: []string{
"--output", "foo",
"--delete-timeout", "2m",
},
inventory: validInventory,
namespace: "testns",
destroyCallbackFunc: func(t *testing.T, _ inventory.Info) {
t.FailNow()
destroyCallbackFunc: func(t *testing.T, r *Runner, _ inventory.Info) {
assert.Equal(t, 2*time.Minute, r.deleteTimeout)
},
expectedErrorMsg: "unknown output type \"foo\"",
},
"fetches the correct inventory information from the Kptfile": {
"destroy reads inventory from Kptfile": {
args: []string{
"--inventory-policy", "adopt",
"--output", "events",
},
inventory: &kptfilev1.Inventory{
Namespace: "my-ns",
Name: "my-name",
InventoryID: "my-inv-id",
},
inventory: validInventory,
namespace: "testns",
destroyCallbackFunc: func(t *testing.T, inv inventory.Info) {
destroyCallbackFunc: func(t *testing.T, _ *Runner, inv inventory.Info) {
assert.Equal(t, "my-ns", inv.Namespace())
assert.Equal(t, "my-name", inv.Name())
assert.Equal(t, "my-inv-id", inv.ID())
Expand All @@ -103,13 +127,14 @@ func TestCmd(t *testing.T) {

runner := NewRunner(fake.CtxWithDefaultPrinter(), tf, ioStreams)
runner.Command.SetArgs(tc.args)
runner.destroyRunner = func(_ *Runner, inv inventory.Info, _ common.DryRunStrategy) error {
tc.destroyCallbackFunc(t, inv)
// Stub out the destroy execution to isolate flag parsing and
// validation from actual cluster interaction.
runner.destroyRunner = func(r *Runner, inv inventory.Info, _ common.DryRunStrategy) error {
tc.destroyCallbackFunc(t, r, inv)
return nil
}
err := runner.Command.Execute()

// Check if there should be an error
if tc.expectedErrorMsg != "" {
if !assert.Error(t, err) {
t.FailNow()
Expand Down
10 changes: 10 additions & 0 deletions documentation/content/en/reference/cli/live/destroy/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,16 @@ PKG_PATH | -:
* none: Do not save any status information in the inventory.

The default value is `all`.

--delete-propagation-policy:
The propagation policy that should be used when deleting resources. The
default value here is 'Background'. The other options are 'Foreground' and 'Orphan'.

--delete-timeout:
The threshold for how long to wait for all resources to be deleted before
giving up. If this flag is not set, kpt live destroy will wait until
interrupted. In most cases, it would also make sense to set the
--delete-propagation-policy to Foreground when this flag is set.
```

<!--mdtogo-->
Expand Down
10 changes: 10 additions & 0 deletions internal/docs/generated/livedocs/docs.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.