Merge pull request #59851 from nilebox/kubectl-foreground-deletion

Automatic merge from submit-queue. If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

Use DeleteOptions.PropagationPolicy instead of OrphanDependents (deprecated) in kubectl

**What this PR does / why we need it**:
Replaces the deprecated `DeleteOptions.OrphanDependents` deletion option with `DeleteOptions.PropagationPolicy`. It will improve the cascade deletion by using `Foreground` GC deletion instead of the old `OrphanDependents: false` which has a confusing behavior (leaves orphans if children has finalizers set).

**Which issue(s) this PR fixes**:
Fixes #59850

**Special notes for your reviewer**:

**Release note**:

```release-note
Use DeleteOptions.PropagationPolicy instead of OrphanDependents in kubectl 
```
pull/8/head
Kubernetes Submit Queue 2018-05-23 08:53:23 -07:00 committed by GitHub
commit 8f4674d267
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 44 additions and 36 deletions

View File

@ -1838,7 +1838,7 @@ run_non_native_resource_tests() {
kubectl "${kube_flags[@]}" delete resources myobj --cascade=true kubectl "${kube_flags[@]}" delete resources myobj --cascade=true
# Make sure it's gone # Make sure it's gone
kube::test::get_object_assert resources "{{range.items}}{{$id_field}}:{{end}}" '' kube::test::wait_object_assert resources "{{range.items}}{{$id_field}}:{{end}}" ''
# Test that we can create a new resource of type Foo # Test that we can create a new resource of type Foo
kubectl "${kube_flags[@]}" create -f hack/testdata/CRD/foo.yaml "${kube_flags[@]}" kubectl "${kube_flags[@]}" create -f hack/testdata/CRD/foo.yaml "${kube_flags[@]}"
@ -1919,7 +1919,7 @@ run_non_native_resource_tests() {
kubectl "${kube_flags[@]}" delete foos test --cascade=true kubectl "${kube_flags[@]}" delete foos test --cascade=true
# Make sure it's gone # Make sure it's gone
kube::test::get_object_assert foos "{{range.items}}{{$id_field}}:{{end}}" '' kube::test::wait_object_assert foos "{{range.items}}{{$id_field}}:{{end}}" ''
# Test that we can create a new resource of type Bar # Test that we can create a new resource of type Bar
kubectl "${kube_flags[@]}" create -f hack/testdata/CRD/bar.yaml "${kube_flags[@]}" kubectl "${kube_flags[@]}" create -f hack/testdata/CRD/bar.yaml "${kube_flags[@]}"

View File

@ -302,12 +302,12 @@ func (o *DeleteOptions) DeleteResult(r *resource.Result) error {
found++ found++
// if we're here, it means that cascade=false (not the default), so we should orphan as requested // if we're here, it means that cascade=false (not the default), so we should orphan as requested
orphan := true
options := &metav1.DeleteOptions{} options := &metav1.DeleteOptions{}
if o.GracePeriod >= 0 { if o.GracePeriod >= 0 {
options = metav1.NewDeleteOptions(int64(o.GracePeriod)) options = metav1.NewDeleteOptions(int64(o.GracePeriod))
} }
options.OrphanDependents = &orphan policy := metav1.DeletePropagationOrphan
options.PropagationPolicy = &policy
return o.deleteResource(info, options) return o.deleteResource(info, options)
}) })
if err != nil { if err != nil {
@ -350,8 +350,8 @@ func (o *DeleteOptions) DeleteResult(r *resource.Result) error {
} }
func (o *DeleteOptions) cascadingDeleteResource(info *resource.Info) error { func (o *DeleteOptions) cascadingDeleteResource(info *resource.Info) error {
falseVar := false policy := metav1.DeletePropagationForeground
return o.deleteResource(info, &metav1.DeleteOptions{OrphanDependents: &falseVar}) return o.deleteResource(info, &metav1.DeleteOptions{PropagationPolicy: &policy})
} }
func (o *DeleteOptions) deleteResource(info *resource.Info, deleteOptions *metav1.DeleteOptions) error { func (o *DeleteOptions) deleteResource(info *resource.Info, deleteOptions *metav1.DeleteOptions) error {

View File

@ -104,17 +104,17 @@ func TestDeleteObjectByTuple(t *testing.T) {
} }
} }
func hasExpectedOrphanDependents(body io.ReadCloser, expectedOrphanDependents *bool) bool { func hasExpectedPropagationPolicy(body io.ReadCloser, policy *metav1.DeletionPropagation) bool {
if body == nil || expectedOrphanDependents == nil { if body == nil || policy == nil {
return body == nil && expectedOrphanDependents == nil return body == nil && policy == nil
} }
var parsedBody metav1.DeleteOptions var parsedBody metav1.DeleteOptions
rawBody, _ := ioutil.ReadAll(body) rawBody, _ := ioutil.ReadAll(body)
json.Unmarshal(rawBody, &parsedBody) json.Unmarshal(rawBody, &parsedBody)
if parsedBody.OrphanDependents == nil { if parsedBody.PropagationPolicy == nil {
return false return false
} }
return *expectedOrphanDependents == *parsedBody.OrphanDependents return *policy == *parsedBody.PropagationPolicy
} }
// Tests that DeleteOptions.OrphanDependents is appropriately set while deleting objects. // Tests that DeleteOptions.OrphanDependents is appropriately set while deleting objects.
@ -127,13 +127,13 @@ func TestOrphanDependentsInDeleteObject(t *testing.T) {
codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...) codec := legacyscheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
var expectedOrphanDependents *bool var policy *metav1.DeletionPropagation
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m, b := req.URL.Path, req.Method, req.Body; { switch p, m, b := req.URL.Path, req.Method, req.Body; {
case p == "/namespaces/test/secrets/mysecret" && m == "DELETE" && hasExpectedOrphanDependents(b, expectedOrphanDependents): case p == "/namespaces/test/secrets/mysecret" && m == "DELETE" && hasExpectedPropagationPolicy(b, policy):
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &rc.Items[0])}, nil return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &rc.Items[0])}, nil
default: default:
@ -143,9 +143,9 @@ func TestOrphanDependentsInDeleteObject(t *testing.T) {
} }
tf.Namespace = "test" tf.Namespace = "test"
// DeleteOptions.OrphanDependents should be false, when cascade is true (default). // DeleteOptions.PropagationPolicy should be Foreground, when cascade is true (default).
falseVar := false foregroundPolicy := metav1.DeletePropagationForeground
expectedOrphanDependents = &falseVar policy = &foregroundPolicy
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")
@ -156,8 +156,8 @@ func TestOrphanDependentsInDeleteObject(t *testing.T) {
} }
// Test that delete options should be set to orphan when cascade is false. // Test that delete options should be set to orphan when cascade is false.
trueVar := true orphanPolicy := metav1.DeletePropagationOrphan
expectedOrphanDependents = &trueVar 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")

View File

@ -211,8 +211,10 @@ func (reaper *ReplicationControllerReaper) Stop(namespace, name string, timeout
return err return err
} }
} }
falseVar := false // Using a background deletion policy because the replication controller
deleteOptions := &metav1.DeleteOptions{OrphanDependents: &falseVar} // has already been scaled down.
policy := metav1.DeletePropagationBackground
deleteOptions := &metav1.DeleteOptions{PropagationPolicy: &policy}
return rc.Delete(name, deleteOptions) return rc.Delete(name, deleteOptions)
} }
@ -282,8 +284,10 @@ func (reaper *ReplicaSetReaper) Stop(namespace, name string, timeout time.Durati
} }
} }
falseVar := false // Using a background deletion policy because the replica set has already
deleteOptions := &metav1.DeleteOptions{OrphanDependents: &falseVar} // been scaled down.
policy := metav1.DeletePropagationBackground
deleteOptions := &metav1.DeleteOptions{PropagationPolicy: &policy}
return rsc.Delete(name, deleteOptions) return rsc.Delete(name, deleteOptions)
} }
@ -319,8 +323,10 @@ func (reaper *DaemonSetReaper) Stop(namespace, name string, timeout time.Duratio
return err return err
} }
falseVar := false // Using a background deletion policy because the daemon set has already
deleteOptions := &metav1.DeleteOptions{OrphanDependents: &falseVar} // been scaled down.
policy := metav1.DeletePropagationBackground
deleteOptions := &metav1.DeleteOptions{PropagationPolicy: &policy}
return reaper.client.DaemonSets(namespace).Delete(name, deleteOptions) return reaper.client.DaemonSets(namespace).Delete(name, deleteOptions)
} }
@ -347,8 +353,10 @@ func (reaper *StatefulSetReaper) Stop(namespace, name string, timeout time.Durat
// TODO: Cleanup volumes? We don't want to accidentally delete volumes from // TODO: Cleanup volumes? We don't want to accidentally delete volumes from
// stop, so just leave this up to the statefulset. // stop, so just leave this up to the statefulset.
falseVar := false // Using a background deletion policy because the stateful set has already
deleteOptions := &metav1.DeleteOptions{OrphanDependents: &falseVar} // been scaled down.
policy := metav1.DeletePropagationBackground
deleteOptions := &metav1.DeleteOptions{PropagationPolicy: &policy}
return statefulsets.Delete(name, deleteOptions) return statefulsets.Delete(name, deleteOptions)
} }
@ -394,8 +402,8 @@ func (reaper *JobReaper) Stop(namespace, name string, timeout time.Duration, gra
return utilerrors.NewAggregate(errList) return utilerrors.NewAggregate(errList)
} }
// once we have all the pods removed we can safely remove the job itself. // once we have all the pods removed we can safely remove the job itself.
falseVar := false policy := metav1.DeletePropagationBackground
deleteOptions := &metav1.DeleteOptions{OrphanDependents: &falseVar} deleteOptions := &metav1.DeleteOptions{PropagationPolicy: &policy}
return jobs.Delete(name, deleteOptions) return jobs.Delete(name, deleteOptions)
} }
@ -415,9 +423,9 @@ func (reaper *DeploymentReaper) Stop(namespace, name string, timeout time.Durati
return err return err
} }
if deployment.Initializers != nil { if deployment.Initializers != nil {
var falseVar = false policy := metav1.DeletePropagationBackground
nonOrphanOption := metav1.DeleteOptions{OrphanDependents: &falseVar} deleteOptions := &metav1.DeleteOptions{PropagationPolicy: &policy}
return deployments.Delete(name, &nonOrphanOption) return deployments.Delete(name, deleteOptions)
} }
// Use observedGeneration to determine if the deployment controller noticed the pause. // Use observedGeneration to determine if the deployment controller noticed the pause.
@ -459,9 +467,9 @@ func (reaper *DeploymentReaper) Stop(namespace, name string, timeout time.Durati
// Delete deployment at the end. // Delete deployment at the end.
// Note: We delete deployment at the end so that if removing RSs fails, we at least have the deployment to retry. // Note: We delete deployment at the end so that if removing RSs fails, we at least have the deployment to retry.
var falseVar = false policy := metav1.DeletePropagationBackground
nonOrphanOption := metav1.DeleteOptions{OrphanDependents: &falseVar} deleteOptions := &metav1.DeleteOptions{PropagationPolicy: &policy}
return deployments.Delete(name, &nonOrphanOption) return deployments.Delete(name, deleteOptions)
} }
type updateDeploymentFunc func(d *extensions.Deployment) type updateDeploymentFunc func(d *extensions.Deployment)

View File

@ -549,8 +549,8 @@ func Rename(c coreclient.ReplicationControllersGetter, rc *api.ReplicationContro
rc.Name = newName rc.Name = newName
rc.ResourceVersion = "" rc.ResourceVersion = ""
// First delete the oldName RC and orphan its pods. // First delete the oldName RC and orphan its pods.
trueVar := true policy := metav1.DeletePropagationOrphan
err := c.ReplicationControllers(rc.Namespace).Delete(oldName, &metav1.DeleteOptions{OrphanDependents: &trueVar}) err := c.ReplicationControllers(rc.Namespace).Delete(oldName, &metav1.DeleteOptions{PropagationPolicy: &policy})
if err != nil && !errors.IsNotFound(err) { if err != nil && !errors.IsNotFound(err) {
return err return err
} }