Skip to content

Commit

Permalink
Merge pull request #37709 from saad-ali/automated-cherry-pick-of-#372…
Browse files Browse the repository at this point in the history
…63-upstream-release-1.5

Automated cherry pick of #37263 upstream release 1.5
  • Loading branch information
saad-ali committed Nov 30, 2016
2 parents 3ddc4ec + 4d914da commit 01dd9a7
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 47 deletions.
10 changes: 4 additions & 6 deletions hack/make-rules/test-cmd.sh
Original file line number Diff line number Diff line change
Expand Up @@ -490,10 +490,8 @@ runTests() {
# Pre-condition: valid-pod POD exists
kubectl create "${kube_flags[@]}" -f test/fixtures/doc-yaml/admin/limitrange/valid-pod.yaml
kube::test::get_object_assert pods "{{range.items}}{{$id_field}}:{{end}}" 'valid-pod:'
# Command fails without --force
! kubectl delete pod valid-pod "${kube_flags[@]}" --grace-period=0
# Command succeds with --force
kubectl delete pod valid-pod "${kube_flags[@]}" --grace-period=0 --force
# Command succeeds without --force by waiting
kubectl delete pod valid-pod "${kube_flags[@]}" --grace-period=0
# Post-condition: valid-pod POD doesn't exist
kube::test::get_object_assert pods "{{range.items}}{{$id_field}}:{{end}}" ''

Expand Down Expand Up @@ -2226,7 +2224,7 @@ __EOF__
## Set resource limits/request of a deployment
# Pre-condition: no deployment exists
kube::test::get_object_assert deployment "{{range.items}}{{$id_field}}:{{end}}" ''
# Set resources of a local file without talking to the server
# Set resources of a local file without talking to the server
kubectl set resources -f hack/testdata/deployment-multicontainer-resources.yaml -c=perl --limits=cpu=300m --requests=cpu=300m --local -o yaml "${kube_flags[@]}"
! kubectl set resources -f hack/testdata/deployment-multicontainer-resources.yaml -c=perl --limits=cpu=300m --requests=cpu=300m --dry-run -o yaml "${kube_flags[@]}"
# Create a deployment
Expand All @@ -2249,7 +2247,7 @@ __EOF__
kube::test::get_object_assert deployment "{{range.items}}{{(index .spec.template.spec.containers 0).resources.limits.cpu}}:{{end}}" "200m:"
kube::test::get_object_assert deployment "{{range.items}}{{(index .spec.template.spec.containers 1).resources.limits.cpu}}:{{end}}" "300m:"
kube::test::get_object_assert deployment "{{range.items}}{{(index .spec.template.spec.containers 1).resources.requests.cpu}}:{{end}}" "300m:"
# Show dry-run works on running deployments
# Show dry-run works on running deployments
kubectl set resources deployment nginx-deployment-resources -c=perl --limits=cpu=400m --requests=cpu=400m --dry-run -o yaml "${kube_flags[@]}"
! kubectl set resources deployment nginx-deployment-resources -c=perl --limits=cpu=400m --requests=cpu=400m --local -o yaml "${kube_flags[@]}"
kube::test::get_object_assert deployment "{{range.items}}{{(index .spec.template.spec.containers 0).resources.limits.cpu}}:{{end}}" "200m:"
Expand Down
2 changes: 1 addition & 1 deletion pkg/kubectl/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ func NewKubectlCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cob
NewCmdGet(f, out, err),
NewCmdExplain(f, out, err),
NewCmdEdit(f, out, err),
NewCmdDelete(f, out),
NewCmdDelete(f, out, err),
},
},
{
Expand Down
51 changes: 44 additions & 7 deletions pkg/kubectl/cmd/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/wait"
)

var (
Expand Down Expand Up @@ -88,7 +89,7 @@ var (
kubectl delete pods --all`)
)

func NewCmdDelete(f cmdutil.Factory, out io.Writer) *cobra.Command {
func NewCmdDelete(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
options := &resource.FilenameOptions{}

// retrieve a list of handled resources from printer as valid args
Expand All @@ -109,7 +110,7 @@ func NewCmdDelete(f cmdutil.Factory, out io.Writer) *cobra.Command {
Example: delete_example,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(cmdutil.ValidateOutputArgs(cmd))
err := RunDelete(f, out, cmd, args, options)
err := RunDelete(f, out, errOut, cmd, args, options)
cmdutil.CheckErr(err)
},
SuggestFor: []string{"rm"},
Expand All @@ -131,7 +132,7 @@ func NewCmdDelete(f cmdutil.Factory, out io.Writer) *cobra.Command {
return cmd
}

func RunDelete(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string, options *resource.FilenameOptions) error {
func RunDelete(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args []string, options *resource.FilenameOptions) error {
cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
if err != nil {
return err
Expand Down Expand Up @@ -169,25 +170,35 @@ func RunDelete(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri
}

gracePeriod := cmdutil.GetFlagInt(cmd, "grace-period")
force := cmdutil.GetFlagBool(cmd, "force")
if cmdutil.GetFlagBool(cmd, "now") {
if gracePeriod != -1 {
return fmt.Errorf("--now and --grace-period cannot be specified together")
}
gracePeriod = 1
}
if gracePeriod == 0 && !cmdutil.GetFlagBool(cmd, "force") {
return fmt.Errorf("Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely. You must pass --force to delete with grace period 0.")
wait := false
if gracePeriod == 0 {
if force {
fmt.Fprintf(errOut, "warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.\n")
} else {
// To preserve backwards compatibility, but prevent accidental data loss, we convert --grace-period=0
// into --grace-period=1 and wait until the object is successfully deleted. Users may provide --force
// to bypass this wait.
wait = true
gracePeriod = 1
}
}

shortOutput := cmdutil.GetFlagString(cmd, "output") == "name"
// By default use a reaper to delete all related resources.
if cmdutil.GetFlagBool(cmd, "cascade") {
return ReapResult(r, f, out, cmdutil.GetFlagBool(cmd, "cascade"), ignoreNotFound, cmdutil.GetFlagDuration(cmd, "timeout"), gracePeriod, shortOutput, mapper, false)
return ReapResult(r, f, out, cmdutil.GetFlagBool(cmd, "cascade"), ignoreNotFound, cmdutil.GetFlagDuration(cmd, "timeout"), gracePeriod, wait, shortOutput, mapper, false)
}
return DeleteResult(r, out, ignoreNotFound, shortOutput, mapper)
}

func ReapResult(r *resource.Result, f cmdutil.Factory, out io.Writer, isDefaultDelete, ignoreNotFound bool, timeout time.Duration, gracePeriod int, shortOutput bool, mapper meta.RESTMapper, quiet bool) error {
func ReapResult(r *resource.Result, f cmdutil.Factory, out io.Writer, isDefaultDelete, ignoreNotFound bool, timeout time.Duration, gracePeriod int, waitForDeletion, shortOutput bool, mapper meta.RESTMapper, quiet bool) error {
found := 0
if ignoreNotFound {
r = r.IgnoreErrors(errors.IsNotFound)
Expand All @@ -212,6 +223,11 @@ func ReapResult(r *resource.Result, f cmdutil.Factory, out io.Writer, isDefaultD
if err := reaper.Stop(info.Namespace, info.Name, timeout, options); err != nil {
return cmdutil.AddSourceToErr("stopping", info.Source, err)
}
if waitForDeletion {
if err := waitForObjectDeletion(info, timeout); err != nil {
return cmdutil.AddSourceToErr("stopping", info.Source, err)
}
}
if !quiet {
cmdutil.PrintSuccess(mapper, shortOutput, out, info.Mapping.Resource, info.Name, false, "deleted")
}
Expand Down Expand Up @@ -254,3 +270,24 @@ func deleteResource(info *resource.Info, out io.Writer, shortOutput bool, mapper
cmdutil.PrintSuccess(mapper, shortOutput, out, info.Mapping.Resource, info.Name, false, "deleted")
return nil
}

// objectDeletionWaitInterval is the interval to wait between checks for deletion. Exposed for testing.
var objectDeletionWaitInterval = time.Second

// waitForObjectDeletion refreshes the object, waiting until it is deleted, a timeout is reached, or
// an error is encountered. It checks once a second.
func waitForObjectDeletion(info *resource.Info, timeout time.Duration) error {
copied := *info
info = &copied
// TODO: refactor Reaper so that we can pass the "wait" option into it, and then check for UID change.
return wait.PollImmediate(objectDeletionWaitInterval, timeout, func() (bool, error) {
switch err := info.Get(); {
case err == nil:
return false, nil
case errors.IsNotFound(err):
return true, nil
default:
return false, err
}
})
}
Loading

0 comments on commit 01dd9a7

Please sign in to comment.