mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-19 18:02:01 +00:00
Support kubectl delete foreground
This commit is contained in:
parent
d8937faf23
commit
383b5f6766
@ -244,7 +244,11 @@ func (o *ApplyOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
o.DeleteOptions = o.DeleteFlags.ToOptions(o.DynamicClient, o.IOStreams)
|
o.DeleteOptions, err = o.DeleteFlags.ToOptions(o.DynamicClient, o.IOStreams)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
err = o.DeleteOptions.FilenameOptions.RequireFilenameOrKustomize()
|
err = o.DeleteOptions.FilenameOptions.RequireFilenameOrKustomize()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -25,6 +25,7 @@ import (
|
|||||||
"github.com/jonboulle/clockwork"
|
"github.com/jonboulle/clockwork"
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
@ -57,10 +58,10 @@ type Patcher struct {
|
|||||||
Overwrite bool
|
Overwrite bool
|
||||||
BackOff clockwork.Clock
|
BackOff clockwork.Clock
|
||||||
|
|
||||||
Force bool
|
Force bool
|
||||||
Cascade bool
|
CascadingStrategy metav1.DeletionPropagation
|
||||||
Timeout time.Duration
|
Timeout time.Duration
|
||||||
GracePeriod int
|
GracePeriod int
|
||||||
|
|
||||||
// If set, forces the patch against a specific resourceVersion
|
// If set, forces the patch against a specific resourceVersion
|
||||||
ResourceVersion *string
|
ResourceVersion *string
|
||||||
@ -78,21 +79,21 @@ func newPatcher(o *ApplyOptions, info *resource.Info, helper *resource.Helper) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &Patcher{
|
return &Patcher{
|
||||||
Mapping: info.Mapping,
|
Mapping: info.Mapping,
|
||||||
Helper: helper,
|
Helper: helper,
|
||||||
Overwrite: o.Overwrite,
|
Overwrite: o.Overwrite,
|
||||||
BackOff: clockwork.NewRealClock(),
|
BackOff: clockwork.NewRealClock(),
|
||||||
Force: o.DeleteOptions.ForceDeletion,
|
Force: o.DeleteOptions.ForceDeletion,
|
||||||
Cascade: o.DeleteOptions.Cascade,
|
CascadingStrategy: o.DeleteOptions.CascadingStrategy,
|
||||||
Timeout: o.DeleteOptions.Timeout,
|
Timeout: o.DeleteOptions.Timeout,
|
||||||
GracePeriod: o.DeleteOptions.GracePeriod,
|
GracePeriod: o.DeleteOptions.GracePeriod,
|
||||||
OpenapiSchema: openapiSchema,
|
OpenapiSchema: openapiSchema,
|
||||||
Retries: maxPatchRetry,
|
Retries: maxPatchRetry,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Patcher) delete(namespace, name string) error {
|
func (p *Patcher) delete(namespace, name string) error {
|
||||||
options := asDeleteOptions(p.Cascade, p.GracePeriod)
|
options := asDeleteOptions(p.CascadingStrategy, p.GracePeriod)
|
||||||
_, err := p.Helper.DeleteWithOptions(namespace, name, &options)
|
_, err := p.Helper.DeleteWithOptions(namespace, name, &options)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -41,9 +41,9 @@ type pruner struct {
|
|||||||
labelSelector string
|
labelSelector string
|
||||||
fieldSelector string
|
fieldSelector string
|
||||||
|
|
||||||
cascade bool
|
cascadingStrategy metav1.DeletionPropagation
|
||||||
dryRunStrategy cmdutil.DryRunStrategy
|
dryRunStrategy cmdutil.DryRunStrategy
|
||||||
gracePeriod int
|
gracePeriod int
|
||||||
|
|
||||||
toPrinter func(string) (printers.ResourcePrinter, error)
|
toPrinter func(string) (printers.ResourcePrinter, error)
|
||||||
|
|
||||||
@ -59,9 +59,9 @@ func newPruner(o *ApplyOptions) pruner {
|
|||||||
visitedUids: o.VisitedUids,
|
visitedUids: o.VisitedUids,
|
||||||
visitedNamespaces: o.VisitedNamespaces,
|
visitedNamespaces: o.VisitedNamespaces,
|
||||||
|
|
||||||
cascade: o.DeleteOptions.Cascade,
|
cascadingStrategy: o.DeleteOptions.CascadingStrategy,
|
||||||
dryRunStrategy: o.DryRunStrategy,
|
dryRunStrategy: o.DryRunStrategy,
|
||||||
gracePeriod: o.DeleteOptions.GracePeriod,
|
gracePeriod: o.DeleteOptions.GracePeriod,
|
||||||
|
|
||||||
toPrinter: o.ToPrinter,
|
toPrinter: o.ToPrinter,
|
||||||
|
|
||||||
@ -139,27 +139,23 @@ func (p *pruner) prune(namespace string, mapping *meta.RESTMapping) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *pruner) delete(namespace, name string, mapping *meta.RESTMapping) error {
|
func (p *pruner) delete(namespace, name string, mapping *meta.RESTMapping) error {
|
||||||
return runDelete(namespace, name, mapping, p.dynamicClient, p.cascade, p.gracePeriod, p.dryRunStrategy == cmdutil.DryRunServer)
|
return runDelete(namespace, name, mapping, p.dynamicClient, p.cascadingStrategy, p.gracePeriod, p.dryRunStrategy == cmdutil.DryRunServer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runDelete(namespace, name string, mapping *meta.RESTMapping, c dynamic.Interface, cascade bool, gracePeriod int, serverDryRun bool) error {
|
func runDelete(namespace, name string, mapping *meta.RESTMapping, c dynamic.Interface, cascadingStrategy metav1.DeletionPropagation, gracePeriod int, serverDryRun bool) error {
|
||||||
options := asDeleteOptions(cascade, gracePeriod)
|
options := asDeleteOptions(cascadingStrategy, gracePeriod)
|
||||||
if serverDryRun {
|
if serverDryRun {
|
||||||
options.DryRun = []string{metav1.DryRunAll}
|
options.DryRun = []string{metav1.DryRunAll}
|
||||||
}
|
}
|
||||||
return c.Resource(mapping.Resource).Namespace(namespace).Delete(context.TODO(), name, options)
|
return c.Resource(mapping.Resource).Namespace(namespace).Delete(context.TODO(), name, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
func asDeleteOptions(cascade bool, gracePeriod int) metav1.DeleteOptions {
|
func asDeleteOptions(cascadingStrategy metav1.DeletionPropagation, gracePeriod int) metav1.DeleteOptions {
|
||||||
options := metav1.DeleteOptions{}
|
options := metav1.DeleteOptions{}
|
||||||
if gracePeriod >= 0 {
|
if gracePeriod >= 0 {
|
||||||
options = *metav1.NewDeleteOptions(int64(gracePeriod))
|
options = *metav1.NewDeleteOptions(int64(gracePeriod))
|
||||||
}
|
}
|
||||||
policy := metav1.DeletePropagationForeground
|
options.PropagationPolicy = &cascadingStrategy
|
||||||
if !cascade {
|
|
||||||
policy = metav1.DeletePropagationOrphan
|
|
||||||
}
|
|
||||||
options.PropagationPolicy = &policy
|
|
||||||
return options
|
return options
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,8 +102,8 @@ type DeleteOptions struct {
|
|||||||
FieldSelector string
|
FieldSelector string
|
||||||
DeleteAll bool
|
DeleteAll bool
|
||||||
DeleteAllNamespaces bool
|
DeleteAllNamespaces bool
|
||||||
|
CascadingStrategy metav1.DeletionPropagation
|
||||||
IgnoreNotFound bool
|
IgnoreNotFound bool
|
||||||
Cascade bool
|
|
||||||
DeleteNow bool
|
DeleteNow bool
|
||||||
ForceDeletion bool
|
ForceDeletion bool
|
||||||
WaitForDeletion bool
|
WaitForDeletion bool
|
||||||
@ -136,7 +136,8 @@ func NewCmdDelete(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra
|
|||||||
Long: deleteLong,
|
Long: deleteLong,
|
||||||
Example: deleteExample,
|
Example: deleteExample,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
o := deleteFlags.ToOptions(nil, streams)
|
o, err := deleteFlags.ToOptions(nil, streams)
|
||||||
|
cmdutil.CheckErr(err)
|
||||||
cmdutil.CheckErr(o.Complete(f, args, cmd))
|
cmdutil.CheckErr(o.Complete(f, args, cmd))
|
||||||
cmdutil.CheckErr(o.Validate())
|
cmdutil.CheckErr(o.Validate())
|
||||||
cmdutil.CheckErr(o.RunDelete(f))
|
cmdutil.CheckErr(o.RunDelete(f))
|
||||||
@ -301,11 +302,7 @@ func (o *DeleteOptions) DeleteResult(r *resource.Result) error {
|
|||||||
if o.GracePeriod >= 0 {
|
if o.GracePeriod >= 0 {
|
||||||
options = metav1.NewDeleteOptions(int64(o.GracePeriod))
|
options = metav1.NewDeleteOptions(int64(o.GracePeriod))
|
||||||
}
|
}
|
||||||
policy := metav1.DeletePropagationBackground
|
options.PropagationPolicy = &o.CascadingStrategy
|
||||||
if !o.Cascade {
|
|
||||||
policy = metav1.DeletePropagationOrphan
|
|
||||||
}
|
|
||||||
options.PropagationPolicy = &policy
|
|
||||||
|
|
||||||
if warnClusterScope && info.Mapping.Scope.Name() == meta.RESTScopeNameRoot {
|
if warnClusterScope && info.Mapping.Scope.Name() == meta.RESTScopeNameRoot {
|
||||||
fmt.Fprintf(o.ErrOut, "warning: deleting cluster-scoped resources, not scoped to the provided namespace\n")
|
fmt.Fprintf(o.ErrOut, "warning: deleting cluster-scoped resources, not scoped to the provided namespace\n")
|
||||||
|
@ -17,12 +17,16 @@ limitations under the License.
|
|||||||
package delete
|
package delete
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||||
"k8s.io/client-go/dynamic"
|
"k8s.io/client-go/dynamic"
|
||||||
|
"k8s.io/klog/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DeleteFlags composes common printer flag structs
|
// DeleteFlags composes common printer flag structs
|
||||||
@ -32,20 +36,20 @@ type DeleteFlags struct {
|
|||||||
LabelSelector *string
|
LabelSelector *string
|
||||||
FieldSelector *string
|
FieldSelector *string
|
||||||
|
|
||||||
All *bool
|
All *bool
|
||||||
AllNamespaces *bool
|
AllNamespaces *bool
|
||||||
Cascade *bool
|
CascadingStrategy *string
|
||||||
Force *bool
|
Force *bool
|
||||||
GracePeriod *int
|
GracePeriod *int
|
||||||
IgnoreNotFound *bool
|
IgnoreNotFound *bool
|
||||||
Now *bool
|
Now *bool
|
||||||
Timeout *time.Duration
|
Timeout *time.Duration
|
||||||
Wait *bool
|
Wait *bool
|
||||||
Output *string
|
Output *string
|
||||||
Raw *string
|
Raw *string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *DeleteFlags) ToOptions(dynamicClient dynamic.Interface, streams genericclioptions.IOStreams) *DeleteOptions {
|
func (f *DeleteFlags) ToOptions(dynamicClient dynamic.Interface, streams genericclioptions.IOStreams) (*DeleteOptions, error) {
|
||||||
options := &DeleteOptions{
|
options := &DeleteOptions{
|
||||||
DynamicClient: dynamicClient,
|
DynamicClient: dynamicClient,
|
||||||
IOStreams: streams,
|
IOStreams: streams,
|
||||||
@ -73,8 +77,12 @@ func (f *DeleteFlags) ToOptions(dynamicClient dynamic.Interface, streams generic
|
|||||||
if f.AllNamespaces != nil {
|
if f.AllNamespaces != nil {
|
||||||
options.DeleteAllNamespaces = *f.AllNamespaces
|
options.DeleteAllNamespaces = *f.AllNamespaces
|
||||||
}
|
}
|
||||||
if f.Cascade != nil {
|
if f.CascadingStrategy != nil {
|
||||||
options.Cascade = *f.Cascade
|
var err error
|
||||||
|
options.CascadingStrategy, err = getCascadingStrategy(*f.CascadingStrategy)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if f.Force != nil {
|
if f.Force != nil {
|
||||||
options.ForceDeletion = *f.Force
|
options.ForceDeletion = *f.Force
|
||||||
@ -98,7 +106,7 @@ func (f *DeleteFlags) ToOptions(dynamicClient dynamic.Interface, streams generic
|
|||||||
options.Raw = *f.Raw
|
options.Raw = *f.Raw
|
||||||
}
|
}
|
||||||
|
|
||||||
return options
|
return options, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *DeleteFlags) AddFlags(cmd *cobra.Command) {
|
func (f *DeleteFlags) AddFlags(cmd *cobra.Command) {
|
||||||
@ -118,8 +126,13 @@ func (f *DeleteFlags) AddFlags(cmd *cobra.Command) {
|
|||||||
if f.Force != nil {
|
if f.Force != nil {
|
||||||
cmd.Flags().BoolVar(f.Force, "force", *f.Force, "If true, immediately remove resources from API and bypass graceful deletion. Note that immediate deletion of some resources may result in inconsistency or data loss and requires confirmation.")
|
cmd.Flags().BoolVar(f.Force, "force", *f.Force, "If true, immediately remove resources from API and bypass graceful deletion. Note that immediate deletion of some resources may result in inconsistency or data loss and requires confirmation.")
|
||||||
}
|
}
|
||||||
if f.Cascade != nil {
|
if f.CascadingStrategy != nil {
|
||||||
cmd.Flags().BoolVar(f.Cascade, "cascade", *f.Cascade, "If true, run background cascade deletion of the resources managed by this resource (e.g. Pods created by a ReplicationController). Default true.")
|
cmd.Flags().StringVar(
|
||||||
|
f.CascadingStrategy,
|
||||||
|
"cascade",
|
||||||
|
*f.CascadingStrategy,
|
||||||
|
`Must be "background", "orphan", or "foreground". Selects the deletion cascading strategy for the dependents (e.g. Pods created by a ReplicationController). Defaults to background.`)
|
||||||
|
cmd.Flags().Lookup("cascade").NoOptDefVal = "background"
|
||||||
}
|
}
|
||||||
if f.Now != nil {
|
if f.Now != nil {
|
||||||
cmd.Flags().BoolVar(f.Now, "now", *f.Now, "If true, resources are signaled for immediate shutdown (same as --grace-period=1).")
|
cmd.Flags().BoolVar(f.Now, "now", *f.Now, "If true, resources are signaled for immediate shutdown (same as --grace-period=1).")
|
||||||
@ -146,7 +159,7 @@ func (f *DeleteFlags) AddFlags(cmd *cobra.Command) {
|
|||||||
|
|
||||||
// NewDeleteCommandFlags provides default flags and values for use with the "delete" command
|
// NewDeleteCommandFlags provides default flags and values for use with the "delete" command
|
||||||
func NewDeleteCommandFlags(usage string) *DeleteFlags {
|
func NewDeleteCommandFlags(usage string) *DeleteFlags {
|
||||||
cascade := true
|
cascadingStrategy := "background"
|
||||||
gracePeriod := -1
|
gracePeriod := -1
|
||||||
|
|
||||||
// setup command defaults
|
// setup command defaults
|
||||||
@ -172,8 +185,8 @@ func NewDeleteCommandFlags(usage string) *DeleteFlags {
|
|||||||
LabelSelector: &labelSelector,
|
LabelSelector: &labelSelector,
|
||||||
FieldSelector: &fieldSelector,
|
FieldSelector: &fieldSelector,
|
||||||
|
|
||||||
Cascade: &cascade,
|
CascadingStrategy: &cascadingStrategy,
|
||||||
GracePeriod: &gracePeriod,
|
GracePeriod: &gracePeriod,
|
||||||
|
|
||||||
All: &all,
|
All: &all,
|
||||||
AllNamespaces: &allNamespaces,
|
AllNamespaces: &allNamespaces,
|
||||||
@ -189,7 +202,7 @@ func NewDeleteCommandFlags(usage string) *DeleteFlags {
|
|||||||
|
|
||||||
// NewDeleteFlags provides default flags and values for use in commands outside of "delete"
|
// NewDeleteFlags provides default flags and values for use in commands outside of "delete"
|
||||||
func NewDeleteFlags(usage string) *DeleteFlags {
|
func NewDeleteFlags(usage string) *DeleteFlags {
|
||||||
cascade := true
|
cascadingStrategy := "background"
|
||||||
gracePeriod := -1
|
gracePeriod := -1
|
||||||
|
|
||||||
force := false
|
force := false
|
||||||
@ -203,8 +216,8 @@ func NewDeleteFlags(usage string) *DeleteFlags {
|
|||||||
return &DeleteFlags{
|
return &DeleteFlags{
|
||||||
FileNameFlags: &genericclioptions.FileNameFlags{Usage: usage, Filenames: &filenames, Kustomize: &kustomize, Recursive: &recursive},
|
FileNameFlags: &genericclioptions.FileNameFlags{Usage: usage, Filenames: &filenames, Kustomize: &kustomize, Recursive: &recursive},
|
||||||
|
|
||||||
Cascade: &cascade,
|
CascadingStrategy: &cascadingStrategy,
|
||||||
GracePeriod: &gracePeriod,
|
GracePeriod: &gracePeriod,
|
||||||
|
|
||||||
// add non-defaults
|
// add non-defaults
|
||||||
Force: &force,
|
Force: &force,
|
||||||
@ -212,3 +225,27 @@ func NewDeleteFlags(usage string) *DeleteFlags {
|
|||||||
Wait: &wait,
|
Wait: &wait,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getCascadingStrategy(cascadingFlag string) (metav1.DeletionPropagation, error) {
|
||||||
|
b, err := strconv.ParseBool(cascadingFlag)
|
||||||
|
// The flag is not a boolean
|
||||||
|
if err != nil {
|
||||||
|
switch cascadingFlag {
|
||||||
|
case "orphan":
|
||||||
|
return metav1.DeletePropagationOrphan, nil
|
||||||
|
case "foreground":
|
||||||
|
return metav1.DeletePropagationForeground, nil
|
||||||
|
case "background":
|
||||||
|
return metav1.DeletePropagationBackground, nil
|
||||||
|
default:
|
||||||
|
return metav1.DeletePropagationBackground, fmt.Errorf(`Invalid cascade value (%v). Must be "background", "foreground", or "orphan".`, cascadingFlag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// The flag was a boolean
|
||||||
|
if b {
|
||||||
|
klog.Warningf(`--cascade=%v is deprecated (boolean value) and can be replaced with --cascade=%s.`, cascadingFlag, "background")
|
||||||
|
return metav1.DeletePropagationBackground, nil
|
||||||
|
}
|
||||||
|
klog.Warningf(`--cascade=%v is deprecated (boolean value) and can be replaced with --cascade=%s.`, cascadingFlag, "orphan")
|
||||||
|
return metav1.DeletePropagationOrphan, nil
|
||||||
|
}
|
||||||
|
@ -112,8 +112,8 @@ func hasExpectedPropagationPolicy(body io.ReadCloser, policy *metav1.DeletionPro
|
|||||||
return *policy == *parsedBody.PropagationPolicy
|
return *policy == *parsedBody.PropagationPolicy
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests that DeleteOptions.OrphanDependents is appropriately set while deleting objects.
|
// TestCascadingStrategy tests that DeleteOptions.DeletionPropagation is appropriately set while deleting objects.
|
||||||
func TestOrphanDependentsInDeleteObject(t *testing.T) {
|
func TestCascadingStrategy(t *testing.T) {
|
||||||
cmdtesting.InitTestErrorHandler(t)
|
cmdtesting.InitTestErrorHandler(t)
|
||||||
_, _, rc := cmdtesting.TestData()
|
_, _, rc := cmdtesting.TestData()
|
||||||
|
|
||||||
@ -137,7 +137,7 @@ func TestOrphanDependentsInDeleteObject(t *testing.T) {
|
|||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteOptions.PropagationPolicy should be Background, when cascade is true (default).
|
// DeleteOptions.PropagationPolicy should be Background, when cascading strategy is empty (default).
|
||||||
backgroundPolicy := metav1.DeletePropagationBackground
|
backgroundPolicy := metav1.DeletePropagationBackground
|
||||||
policy = &backgroundPolicy
|
policy = &backgroundPolicy
|
||||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||||
@ -149,13 +149,26 @@ func TestOrphanDependentsInDeleteObject(t *testing.T) {
|
|||||||
t.Errorf("unexpected output: %s", buf.String())
|
t.Errorf("unexpected output: %s", buf.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that delete options should be set to orphan when cascade is false.
|
// DeleteOptions.PropagationPolicy should be Foreground, when cascading strategy is foreground.
|
||||||
|
foregroundPolicy := metav1.DeletePropagationForeground
|
||||||
|
policy = &foregroundPolicy
|
||||||
|
streams, _, buf, _ = genericclioptions.NewTestIOStreams()
|
||||||
|
cmd = NewCmdDelete(tf, streams)
|
||||||
|
cmd.Flags().Set("namespace", "test")
|
||||||
|
cmd.Flags().Set("cascade", "foreground")
|
||||||
|
cmd.Flags().Set("output", "name")
|
||||||
|
cmd.Run(cmd, []string{"secrets/mysecret"})
|
||||||
|
if buf.String() != "secret/mysecret\n" {
|
||||||
|
t.Errorf("unexpected output: %s", buf.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that delete options should be set to orphan when cascading strategy is orphan.
|
||||||
orphanPolicy := metav1.DeletePropagationOrphan
|
orphanPolicy := metav1.DeletePropagationOrphan
|
||||||
policy = &orphanPolicy
|
policy = &orphanPolicy
|
||||||
streams, _, buf, _ = genericclioptions.NewTestIOStreams()
|
streams, _, buf, _ = genericclioptions.NewTestIOStreams()
|
||||||
cmd = NewCmdDelete(tf, streams)
|
cmd = NewCmdDelete(tf, streams)
|
||||||
cmd.Flags().Set("namespace", "test")
|
cmd.Flags().Set("namespace", "test")
|
||||||
cmd.Flags().Set("cascade", "false")
|
cmd.Flags().Set("cascade", "orphan")
|
||||||
cmd.Flags().Set("output", "name")
|
cmd.Flags().Set("output", "name")
|
||||||
cmd.Run(cmd, []string{"secrets/mysecret"})
|
cmd.Run(cmd, []string{"secrets/mysecret"})
|
||||||
if buf.String() != "secret/mysecret\n" {
|
if buf.String() != "secret/mysecret\n" {
|
||||||
@ -427,10 +440,10 @@ func TestDeleteObjectNotFound(t *testing.T) {
|
|||||||
FilenameOptions: resource.FilenameOptions{
|
FilenameOptions: resource.FilenameOptions{
|
||||||
Filenames: []string{"../../../testdata/redis-master-controller.yaml"},
|
Filenames: []string{"../../../testdata/redis-master-controller.yaml"},
|
||||||
},
|
},
|
||||||
GracePeriod: -1,
|
GracePeriod: -1,
|
||||||
Cascade: false,
|
CascadingStrategy: metav1.DeletePropagationOrphan,
|
||||||
Output: "name",
|
Output: "name",
|
||||||
IOStreams: genericclioptions.NewTestIOStreamsDiscard(),
|
IOStreams: genericclioptions.NewTestIOStreamsDiscard(),
|
||||||
}
|
}
|
||||||
err := options.Complete(tf, []string{}, fakecmd())
|
err := options.Complete(tf, []string{}, fakecmd())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -504,13 +517,13 @@ func TestDeleteAllNotFound(t *testing.T) {
|
|||||||
|
|
||||||
// Make sure we can explicitly choose to fail on NotFound errors, even with --all
|
// Make sure we can explicitly choose to fail on NotFound errors, even with --all
|
||||||
options := &DeleteOptions{
|
options := &DeleteOptions{
|
||||||
FilenameOptions: resource.FilenameOptions{},
|
FilenameOptions: resource.FilenameOptions{},
|
||||||
GracePeriod: -1,
|
GracePeriod: -1,
|
||||||
Cascade: false,
|
CascadingStrategy: metav1.DeletePropagationOrphan,
|
||||||
DeleteAll: true,
|
DeleteAll: true,
|
||||||
IgnoreNotFound: false,
|
IgnoreNotFound: false,
|
||||||
Output: "name",
|
Output: "name",
|
||||||
IOStreams: genericclioptions.NewTestIOStreamsDiscard(),
|
IOStreams: genericclioptions.NewTestIOStreamsDiscard(),
|
||||||
}
|
}
|
||||||
err := options.Complete(tf, []string{"services"}, fakecmd())
|
err := options.Complete(tf, []string{"services"}, fakecmd())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -630,10 +643,10 @@ func TestDeleteMultipleObjectContinueOnMissing(t *testing.T) {
|
|||||||
FilenameOptions: resource.FilenameOptions{
|
FilenameOptions: resource.FilenameOptions{
|
||||||
Filenames: []string{"../../../testdata/redis-master-controller.yaml", "../../../testdata/frontend-service.yaml"},
|
Filenames: []string{"../../../testdata/redis-master-controller.yaml", "../../../testdata/frontend-service.yaml"},
|
||||||
},
|
},
|
||||||
GracePeriod: -1,
|
GracePeriod: -1,
|
||||||
Cascade: false,
|
CascadingStrategy: metav1.DeletePropagationOrphan,
|
||||||
Output: "name",
|
Output: "name",
|
||||||
IOStreams: streams,
|
IOStreams: streams,
|
||||||
}
|
}
|
||||||
err := options.Complete(tf, []string{}, fakecmd())
|
err := options.Complete(tf, []string{}, fakecmd())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -801,11 +814,11 @@ func TestResourceErrors(t *testing.T) {
|
|||||||
|
|
||||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||||
options := &DeleteOptions{
|
options := &DeleteOptions{
|
||||||
FilenameOptions: resource.FilenameOptions{},
|
FilenameOptions: resource.FilenameOptions{},
|
||||||
GracePeriod: -1,
|
GracePeriod: -1,
|
||||||
Cascade: false,
|
CascadingStrategy: metav1.DeletePropagationOrphan,
|
||||||
Output: "name",
|
Output: "name",
|
||||||
IOStreams: streams,
|
IOStreams: streams,
|
||||||
}
|
}
|
||||||
err := options.Complete(tf, testCase.args, fakecmd())
|
err := options.Complete(tf, testCase.args, fakecmd())
|
||||||
if !testCase.errFn(err) {
|
if !testCase.errFn(err) {
|
||||||
|
@ -171,7 +171,10 @@ func (o *ReplaceOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []
|
|||||||
return printer.PrintObj(obj, o.Out)
|
return printer.PrintObj(obj, o.Out)
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteOpts := o.DeleteFlags.ToOptions(dynamicClient, o.IOStreams)
|
deleteOpts, err := o.DeleteFlags.ToOptions(dynamicClient, o.IOStreams)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
//Replace will create a resource if it doesn't exist already, so ignore not found error
|
//Replace will create a resource if it doesn't exist already, so ignore not found error
|
||||||
deleteOpts.IgnoreNotFound = true
|
deleteOpts.IgnoreNotFound = true
|
||||||
|
@ -245,7 +245,11 @@ func (o *RunOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
|
|||||||
return printer.PrintObj(obj, o.Out)
|
return printer.PrintObj(obj, o.Out)
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteOpts := o.DeleteFlags.ToOptions(dynamicClient, o.IOStreams)
|
deleteOpts, err := o.DeleteFlags.ToOptions(dynamicClient, o.IOStreams)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
deleteOpts.IgnoreNotFound = true
|
deleteOpts.IgnoreNotFound = true
|
||||||
deleteOpts.WaitForDeletion = false
|
deleteOpts.WaitForDeletion = false
|
||||||
deleteOpts.GracePeriod = -1
|
deleteOpts.GracePeriod = -1
|
||||||
|
@ -199,9 +199,14 @@ func TestRunArgsFollowDashRules(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
deleteFlags := delete.NewDeleteFlags("to use to replace the resource.")
|
deleteFlags := delete.NewDeleteFlags("to use to replace the resource.")
|
||||||
|
deleteOptions, err := deleteFlags.ToOptions(nil, genericclioptions.NewTestIOStreamsDiscard())
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
opts := &RunOptions{
|
opts := &RunOptions{
|
||||||
PrintFlags: printFlags,
|
PrintFlags: printFlags,
|
||||||
DeleteOptions: deleteFlags.ToOptions(nil, genericclioptions.NewTestIOStreamsDiscard()),
|
DeleteOptions: deleteOptions,
|
||||||
|
|
||||||
IOStreams: genericclioptions.NewTestIOStreamsDiscard(),
|
IOStreams: genericclioptions.NewTestIOStreamsDiscard(),
|
||||||
|
|
||||||
@ -371,9 +376,14 @@ func TestGenerateService(t *testing.T) {
|
|||||||
|
|
||||||
ioStreams, _, buff, _ := genericclioptions.NewTestIOStreams()
|
ioStreams, _, buff, _ := genericclioptions.NewTestIOStreams()
|
||||||
deleteFlags := delete.NewDeleteFlags("to use to replace the resource.")
|
deleteFlags := delete.NewDeleteFlags("to use to replace the resource.")
|
||||||
|
deleteOptions, err := deleteFlags.ToOptions(nil, genericclioptions.NewTestIOStreamsDiscard())
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
opts := &RunOptions{
|
opts := &RunOptions{
|
||||||
PrintFlags: printFlags,
|
PrintFlags: printFlags,
|
||||||
DeleteOptions: deleteFlags.ToOptions(nil, genericclioptions.NewTestIOStreamsDiscard()),
|
DeleteOptions: deleteOptions,
|
||||||
|
|
||||||
IOStreams: ioStreams,
|
IOStreams: ioStreams,
|
||||||
|
|
||||||
|
@ -137,7 +137,7 @@ run_kubectl_apply_deployments_tests() {
|
|||||||
|
|
||||||
# cleanup
|
# cleanup
|
||||||
# need to explicitly remove replicasets and pods because we changed the deployment selector and orphaned things
|
# need to explicitly remove replicasets and pods because we changed the deployment selector and orphaned things
|
||||||
kubectl delete deployments,rs,pods --all --cascade=false --grace-period=0
|
kubectl delete deployments,rs,pods --all --cascade=orphan --grace-period=0
|
||||||
# Post-Condition: no Deployments, ReplicaSets, Pods exist
|
# Post-Condition: no Deployments, ReplicaSets, Pods exist
|
||||||
kube::test::wait_object_assert deployments "{{range.items}}{{${id_field:?}}}:{{end}}" ''
|
kube::test::wait_object_assert deployments "{{range.items}}{{${id_field:?}}}:{{end}}" ''
|
||||||
kube::test::wait_object_assert replicasets "{{range.items}}{{${id_field:?}}}:{{end}}" ''
|
kube::test::wait_object_assert replicasets "{{range.items}}{{${id_field:?}}}:{{end}}" ''
|
||||||
@ -246,10 +246,11 @@ run_deployment_tests() {
|
|||||||
# Wait for rs to come up.
|
# Wait for rs to come up.
|
||||||
kube::test::wait_object_assert rs "{{range.items}}{{${rs_replicas_field:?}}}{{end}}" '3'
|
kube::test::wait_object_assert rs "{{range.items}}{{${rs_replicas_field:?}}}{{end}}" '3'
|
||||||
# Deleting the deployment should delete the rs.
|
# Deleting the deployment should delete the rs.
|
||||||
kubectl delete deployment nginx-deployment "${kube_flags[@]:?}"
|
# using empty value in cascade flag to make sure the backward compatibility.
|
||||||
|
kubectl delete deployment nginx-deployment "${kube_flags[@]:?}" --cascade
|
||||||
kube::test::wait_object_assert rs "{{range.items}}{{${id_field:?}}}:{{end}}" ''
|
kube::test::wait_object_assert rs "{{range.items}}{{${id_field:?}}}:{{end}}" ''
|
||||||
|
|
||||||
## Test that rs is not deleted when deployment is deleted with cascade set to false.
|
## Test that rs is not deleted when deployment is deleted with cascading strategy set to orphan.
|
||||||
# Pre-condition: no deployment and rs exist
|
# Pre-condition: no deployment and rs exist
|
||||||
kube::test::get_object_assert deployment "{{range.items}}{{${id_field:?}}}:{{end}}" ''
|
kube::test::get_object_assert deployment "{{range.items}}{{${id_field:?}}}:{{end}}" ''
|
||||||
kube::test::get_object_assert rs "{{range.items}}{{${id_field:?}}}:{{end}}" ''
|
kube::test::get_object_assert rs "{{range.items}}{{${id_field:?}}}:{{end}}" ''
|
||||||
@ -257,8 +258,8 @@ run_deployment_tests() {
|
|||||||
kubectl create deployment nginx-deployment --image=k8s.gcr.io/nginx:test-cmd
|
kubectl create deployment nginx-deployment --image=k8s.gcr.io/nginx:test-cmd
|
||||||
# Wait for rs to come up.
|
# Wait for rs to come up.
|
||||||
kube::test::wait_object_assert rs "{{range.items}}{{${rs_replicas_field:?}}}{{end}}" '1'
|
kube::test::wait_object_assert rs "{{range.items}}{{${rs_replicas_field:?}}}{{end}}" '1'
|
||||||
# Delete the deployment with cascade set to false.
|
# Delete the deployment with cascading strategy set to orphan.
|
||||||
kubectl delete deployment nginx-deployment "${kube_flags[@]:?}" --cascade=false
|
kubectl delete deployment nginx-deployment "${kube_flags[@]:?}" --cascade=orphan
|
||||||
# Wait for the deployment to be deleted and then verify that rs is not
|
# Wait for the deployment to be deleted and then verify that rs is not
|
||||||
# deleted.
|
# deleted.
|
||||||
kube::test::wait_object_assert deployment "{{range.items}}{{${id_field:?}}}:{{end}}" ''
|
kube::test::wait_object_assert deployment "{{range.items}}{{${id_field:?}}}:{{end}}" ''
|
||||||
@ -545,7 +546,7 @@ run_rs_tests() {
|
|||||||
# Post-condition: no pods from frontend replica set
|
# Post-condition: no pods from frontend replica set
|
||||||
kube::test::wait_object_assert 'pods -l "tier=frontend"' "{{range.items}}{{${id_field:?}}}:{{end}}" ''
|
kube::test::wait_object_assert 'pods -l "tier=frontend"' "{{range.items}}{{${id_field:?}}}:{{end}}" ''
|
||||||
|
|
||||||
### Create and then delete a replica set with cascade=false, make sure it doesn't delete pods.
|
### Create and then delete a replica set with cascading strategy set to orphan, make sure it doesn't delete pods.
|
||||||
# Pre-condition: no replica set exists
|
# Pre-condition: no replica set exists
|
||||||
kube::test::get_object_assert rs "{{range.items}}{{${id_field:?}}}:{{end}}" ''
|
kube::test::get_object_assert rs "{{range.items}}{{${id_field:?}}}:{{end}}" ''
|
||||||
# Command
|
# Command
|
||||||
@ -553,7 +554,7 @@ run_rs_tests() {
|
|||||||
# wait for all 3 pods to be set up
|
# wait for all 3 pods to be set up
|
||||||
kube::test::wait_object_assert 'pods -l "tier=frontend"' "{{range.items}}{{${pod_container_name_field:?}}}:{{end}}" 'php-redis:php-redis:php-redis:'
|
kube::test::wait_object_assert 'pods -l "tier=frontend"' "{{range.items}}{{${pod_container_name_field:?}}}:{{end}}" 'php-redis:php-redis:php-redis:'
|
||||||
kube::log::status "Deleting rs"
|
kube::log::status "Deleting rs"
|
||||||
kubectl delete rs frontend "${kube_flags[@]:?}" --cascade=false
|
kubectl delete rs frontend "${kube_flags[@]:?}" --cascade=orphan
|
||||||
# Wait for the rs to be deleted.
|
# Wait for the rs to be deleted.
|
||||||
kube::test::wait_object_assert rs "{{range.items}}{{${id_field:?}}}:{{end}}" ''
|
kube::test::wait_object_assert rs "{{range.items}}{{${id_field:?}}}:{{end}}" ''
|
||||||
# Post-condition: All 3 pods still remain from frontend replica set
|
# Post-condition: All 3 pods still remain from frontend replica set
|
||||||
|
@ -194,8 +194,8 @@ run_non_native_resource_tests() {
|
|||||||
output_message=$(kubectl "${kube_flags[@]}" get kind.mygroup.example.com/myobj -o name)
|
output_message=$(kubectl "${kube_flags[@]}" get kind.mygroup.example.com/myobj -o name)
|
||||||
kube::test::if_has_string "${output_message}" 'kind.mygroup.example.com/myobj'
|
kube::test::if_has_string "${output_message}" 'kind.mygroup.example.com/myobj'
|
||||||
|
|
||||||
# Delete the resource with cascade.
|
# Delete the resource with cascading strategy background.
|
||||||
kubectl "${kube_flags[@]}" delete resources myobj --cascade=true
|
kubectl "${kube_flags[@]}" delete resources myobj --cascade=background
|
||||||
|
|
||||||
# Make sure it's gone
|
# Make sure it's gone
|
||||||
kube::test::wait_object_assert resources "{{range.items}}{{$id_field}}:{{end}}" ''
|
kube::test::wait_object_assert resources "{{range.items}}{{$id_field}}:{{end}}" ''
|
||||||
@ -275,8 +275,8 @@ run_non_native_resource_tests() {
|
|||||||
kubectl "${kube_flags[@]}" describe foos | grep listlabel=true
|
kubectl "${kube_flags[@]}" describe foos | grep listlabel=true
|
||||||
kubectl "${kube_flags[@]}" describe foos | grep itemlabel=true
|
kubectl "${kube_flags[@]}" describe foos | grep itemlabel=true
|
||||||
|
|
||||||
# Delete the resource with cascade.
|
# Delete the resource with cascading strategy background.
|
||||||
kubectl "${kube_flags[@]}" delete foos test --cascade=true
|
kubectl "${kube_flags[@]}" delete foos test --cascade=background
|
||||||
|
|
||||||
# Make sure it's gone
|
# Make sure it's gone
|
||||||
kube::test::wait_object_assert foos "{{range.items}}{{$id_field}}:{{end}}" ''
|
kube::test::wait_object_assert foos "{{range.items}}{{$id_field}}:{{end}}" ''
|
||||||
@ -313,8 +313,8 @@ run_non_native_resource_tests() {
|
|||||||
kill -9 "${patch_pid}"
|
kill -9 "${patch_pid}"
|
||||||
kube::test::if_has_string "${watch_output}" 'bar.company.com/test'
|
kube::test::if_has_string "${watch_output}" 'bar.company.com/test'
|
||||||
|
|
||||||
# Delete the resource without cascade.
|
# Delete the resource with cascading strategy orphan.
|
||||||
kubectl "${kube_flags[@]}" delete bars test --cascade=false
|
kubectl "${kube_flags[@]}" delete bars test --cascade=orphan
|
||||||
|
|
||||||
# Make sure it's gone
|
# Make sure it's gone
|
||||||
kube::test::wait_object_assert bars "{{range.items}}{{$id_field}}:{{end}}" ''
|
kube::test::wait_object_assert bars "{{range.items}}{{$id_field}}:{{end}}" ''
|
||||||
|
@ -90,7 +90,7 @@ run_multi_resources_tests() {
|
|||||||
fi
|
fi
|
||||||
kubectl describe -f "${file}" "${kube_flags[@]}"
|
kubectl describe -f "${file}" "${kube_flags[@]}"
|
||||||
# Command
|
# Command
|
||||||
kubectl replace -f "${replace_file}" --force --cascade "${kube_flags[@]}"
|
kubectl replace -f "${replace_file}" --force --cascade=background "${kube_flags[@]}"
|
||||||
# Post-condition: mock service (and mock2) and mock rc (and mock2) are replaced
|
# Post-condition: mock service (and mock2) and mock rc (and mock2) are replaced
|
||||||
if [ "$has_svc" = true ]; then
|
if [ "$has_svc" = true ]; then
|
||||||
kube::test::get_object_assert 'services mock' "{{${labels_field:?}.status}}" 'replaced'
|
kube::test::get_object_assert 'services mock' "{{${labels_field:?}.status}}" 'replaced'
|
||||||
|
Loading…
Reference in New Issue
Block a user