Merge pull request #8628 from jlowdermilk/delete-not-found

Delete fails on notfound errors.
This commit is contained in:
Tim Hockin 2015-05-27 16:26:41 -07:00
commit eab1ceccd4
9 changed files with 89 additions and 31 deletions

View File

@ -364,6 +364,7 @@ _kubectl_delete()
flags+=("--grace-period=") flags+=("--grace-period=")
flags+=("--help") flags+=("--help")
flags+=("-h") flags+=("-h")
flags+=("--ignore-not-found")
flags+=("--selector=") flags+=("--selector=")
two_word_flags+=("-l") two_word_flags+=("-l")
@ -587,6 +588,7 @@ _kubectl_stop()
flags+=("--grace-period=") flags+=("--grace-period=")
flags+=("--help") flags+=("--help")
flags+=("-h") flags+=("-h")
flags+=("--ignore-not-found")
flags+=("--selector=") flags+=("--selector=")
two_word_flags+=("-l") two_word_flags+=("-l")

View File

@ -42,12 +42,13 @@ $ kubectl delete pods --all
### Options ### Options
``` ```
--all=false: [-all] to select all the specified resources --all=false: [-all] to select all the specified resources.
--cascade=true: If true, cascade the delete resources managed by this resource (e.g. Pods created by a ReplicationController). Default true. --cascade=true: If true, cascade the delete resources managed by this resource (e.g. Pods created by a ReplicationController). Default true.
-f, --filename=[]: Filename, directory, or URL to a file containing the resource to delete -f, --filename=[]: Filename, directory, or URL to a file containing the resource to delete.
--grace-period=-1: Period of time in seconds given to the resource to terminate gracefully. Ignored if negative. --grace-period=-1: Period of time in seconds given to the resource to terminate gracefully. Ignored if negative.
-h, --help=false: help for delete -h, --help=false: help for delete
-l, --selector="": Selector (label query) to filter on --ignore-not-found=false: Treat "resource not found" as a successful delete.
-l, --selector="": Selector (label query) to filter on.
``` ```
### Options inherited from parent commands ### Options inherited from parent commands
@ -82,6 +83,6 @@ $ kubectl delete pods --all
### SEE ALSO ### SEE ALSO
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager * [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
###### Auto generated by spf13/cobra at 2015-05-21 10:33:11.18056941 +0000 UTC ###### Auto generated by spf13/cobra at 2015-05-21 18:30:45.437003409 +0000 UTC
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/kubectl_delete.md?pixel)]() [![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/kubectl_delete.md?pixel)]()

View File

@ -33,11 +33,12 @@ $ kubectl stop -f path/to/resources
### Options ### Options
``` ```
--all=false: [-all] to select all the specified resources --all=false: [-all] to select all the specified resources.
-f, --filename=[]: Filename, directory, or URL to file of resource(s) to be stopped -f, --filename=[]: Filename, directory, or URL to file of resource(s) to be stopped.
--grace-period=-1: Period of time in seconds given to the resource to terminate gracefully. Ignored if negative. --grace-period=-1: Period of time in seconds given to the resource to terminate gracefully. Ignored if negative.
-h, --help=false: help for stop -h, --help=false: help for stop
-l, --selector="": Selector (label query) to filter on --ignore-not-found=false: Treat "resource not found" as a successful stop.
-l, --selector="": Selector (label query) to filter on.
``` ```
### Options inherited from parent commands ### Options inherited from parent commands
@ -72,6 +73,6 @@ $ kubectl stop -f path/to/resources
### SEE ALSO ### SEE ALSO
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager * [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
###### Auto generated by spf13/cobra at 2015-05-21 10:33:11.190996891 +0000 UTC ###### Auto generated by spf13/cobra at 2015-05-21 18:30:45.439945376 +0000 UTC
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/kubectl_stop.md?pixel)]() [![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/kubectl_stop.md?pixel)]()

View File

@ -31,7 +31,7 @@ will be lost along with the rest of the resource.
.SH OPTIONS .SH OPTIONS
.PP .PP
\fB\-\-all\fP=false \fB\-\-all\fP=false
[\-all] to select all the specified resources [\-all] to select all the specified resources.
.PP .PP
\fB\-\-cascade\fP=true \fB\-\-cascade\fP=true
@ -39,7 +39,7 @@ will be lost along with the rest of the resource.
.PP .PP
\fB\-f\fP, \fB\-\-filename\fP=[] \fB\-f\fP, \fB\-\-filename\fP=[]
Filename, directory, or URL to a file containing the resource to delete Filename, directory, or URL to a file containing the resource to delete.
.PP .PP
\fB\-\-grace\-period\fP=\-1 \fB\-\-grace\-period\fP=\-1
@ -49,9 +49,13 @@ will be lost along with the rest of the resource.
\fB\-h\fP, \fB\-\-help\fP=false \fB\-h\fP, \fB\-\-help\fP=false
help for delete help for delete
.PP
\fB\-\-ignore\-not\-found\fP=false
Treat "resource not found" as a successful delete.
.PP .PP
\fB\-l\fP, \fB\-\-selector\fP="" \fB\-l\fP, \fB\-\-selector\fP=""
Selector (label query) to filter on Selector (label query) to filter on.
.SH OPTIONS INHERITED FROM PARENT COMMANDS .SH OPTIONS INHERITED FROM PARENT COMMANDS

View File

@ -23,11 +23,11 @@ If the resource is scalable it will be scaled to 0 before deletion.
.SH OPTIONS .SH OPTIONS
.PP .PP
\fB\-\-all\fP=false \fB\-\-all\fP=false
[\-all] to select all the specified resources [\-all] to select all the specified resources.
.PP .PP
\fB\-f\fP, \fB\-\-filename\fP=[] \fB\-f\fP, \fB\-\-filename\fP=[]
Filename, directory, or URL to file of resource(s) to be stopped Filename, directory, or URL to file of resource(s) to be stopped.
.PP .PP
\fB\-\-grace\-period\fP=\-1 \fB\-\-grace\-period\fP=\-1
@ -37,9 +37,13 @@ If the resource is scalable it will be scaled to 0 before deletion.
\fB\-h\fP, \fB\-\-help\fP=false \fB\-h\fP, \fB\-\-help\fP=false
help for stop help for stop
.PP
\fB\-\-ignore\-not\-found\fP=false
Treat "resource not found" as a successful stop.
.PP .PP
\fB\-l\fP, \fB\-\-selector\fP="" \fB\-l\fP, \fB\-\-selector\fP=""
Selector (label query) to filter on Selector (label query) to filter on.
.SH OPTIONS INHERITED FROM PARENT COMMANDS .SH OPTIONS INHERITED FROM PARENT COMMANDS

View File

@ -92,7 +92,7 @@ if ! hack/verify-gendocs.sh > /dev/null; then
echo "${red}ERROR!" echo "${red}ERROR!"
echo "Some docs are out of sync between CLI and markdown." echo "Some docs are out of sync between CLI and markdown."
echo "To regenerate docs, run:" echo "To regenerate docs, run:"
echo " hack/run-gendocs.sh > docs/kubectl.md" echo " hack/run-gendocs.sh"
exit_code=1 exit_code=1
else else
echo "${green}OK" echo "${green}OK"

View File

@ -69,10 +69,11 @@ func NewCmdDelete(f *cmdutil.Factory, out io.Writer) *cobra.Command {
cmdutil.CheckErr(err) cmdutil.CheckErr(err)
}, },
} }
usage := "Filename, directory, or URL to a file containing the resource to delete" usage := "Filename, directory, or URL to a file containing the resource to delete."
kubectl.AddJsonFilenameFlag(cmd, &filenames, usage) kubectl.AddJsonFilenameFlag(cmd, &filenames, usage)
cmd.Flags().StringP("selector", "l", "", "Selector (label query) to filter on") cmd.Flags().StringP("selector", "l", "", "Selector (label query) to filter on.")
cmd.Flags().Bool("all", false, "[-all] to select all the specified resources") cmd.Flags().Bool("all", false, "[-all] to select all the specified resources.")
cmd.Flags().Bool("ignore-not-found", false, "Treat \"resource not found\" as a successful delete.")
cmd.Flags().Bool("cascade", true, "If true, cascade the delete resources managed by this resource (e.g. Pods created by a ReplicationController). Default true.") cmd.Flags().Bool("cascade", true, "If true, cascade the delete resources managed by this resource (e.g. Pods created by a ReplicationController). Default true.")
cmd.Flags().Int("grace-period", -1, "Period of time in seconds given to the resource to terminate gracefully. Ignored if negative.") cmd.Flags().Int("grace-period", -1, "Period of time in seconds given to the resource to terminate gracefully. Ignored if negative.")
return cmd return cmd
@ -98,20 +99,24 @@ func RunDelete(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []str
return err return err
} }
ignoreNotFound := cmdutil.GetFlagBool(cmd, "ignore-not-found")
// By default use a reaper to delete all related resources. // By default use a reaper to delete all related resources.
if cmdutil.GetFlagBool(cmd, "cascade") { if cmdutil.GetFlagBool(cmd, "cascade") {
return ReapResult(r, f, out, cmdutil.GetFlagBool(cmd, "cascade"), cmdutil.GetFlagInt(cmd, "grace-period")) return ReapResult(r, f, out, cmdutil.GetFlagBool(cmd, "cascade"), ignoreNotFound, cmdutil.GetFlagInt(cmd, "grace-period"))
} }
return DeleteResult(r, out) return DeleteResult(r, out, ignoreNotFound)
} }
func ReapResult(r *resource.Result, f *cmdutil.Factory, out io.Writer, isDefaultDelete bool, gracePeriod int) error { func ReapResult(r *resource.Result, f *cmdutil.Factory, out io.Writer, isDefaultDelete, ignoreNotFound bool, gracePeriod int) error {
found := 0 found := 0
err := r.IgnoreErrors(errors.IsNotFound).Visit(func(info *resource.Info) error { if ignoreNotFound {
r = r.IgnoreErrors(errors.IsNotFound)
}
err := r.Visit(func(info *resource.Info) error {
found++ found++
reaper, err := f.Reaper(info.Mapping) reaper, err := f.Reaper(info.Mapping)
if err != nil { if err != nil {
// If the error is "not found" and the user didn't explicitly ask for stop. // If there is no reaper for this resources and the user didn't explicitly ask for stop.
if kubectl.IsNoSuchReaperError(err) && isDefaultDelete { if kubectl.IsNoSuchReaperError(err) && isDefaultDelete {
return deleteResource(info, out) return deleteResource(info, out)
} }
@ -136,9 +141,12 @@ func ReapResult(r *resource.Result, f *cmdutil.Factory, out io.Writer, isDefault
return nil return nil
} }
func DeleteResult(r *resource.Result, out io.Writer) error { func DeleteResult(r *resource.Result, out io.Writer, ignoreNotFound bool) error {
found := 0 found := 0
err := r.IgnoreErrors(errors.IsNotFound).Visit(func(info *resource.Info) error { if ignoreNotFound {
r = r.IgnoreErrors(errors.IsNotFound)
}
err := r.Visit(func(info *resource.Info) error {
found++ found++
return deleteResource(info, out) return deleteResource(info, out)
}) })

View File

@ -18,13 +18,16 @@ package cmd
import ( import (
"bytes" "bytes"
"fmt"
"net/http" "net/http"
"strings" "strings"
"testing" "testing"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client" "github.com/GoogleCloudPlatform/kubernetes/pkg/client"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
) )
func TestDeleteObjectByTuple(t *testing.T) { func TestDeleteObjectByTuple(t *testing.T) {
@ -120,6 +123,34 @@ func TestDeleteObject(t *testing.T) {
} }
} }
func TestDeleteObjectNotFound(t *testing.T) {
f, tf, codec := NewAPIFactory()
tf.Printer = &testPrinter{}
tf.Client = &client.FakeRESTClient{
Codec: codec,
Client: client.HTTPClientFunc(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
case p == "/namespaces/test/replicationcontrollers/redis-master" && m == "DELETE":
return &http.Response{StatusCode: 404, Body: stringBody("")}, nil
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil
}
}),
}
tf.Namespace = "test"
buf := bytes.NewBuffer([]byte{})
cmd := NewCmdDelete(f, buf)
cmd.Flags().Set("filename", "../../../examples/guestbook/redis-master-controller.json")
cmd.Flags().Set("cascade", "false")
filenames := cmd.Flags().Lookup("filename").Value.(*util.StringList)
err := RunDelete(f, buf, cmd, []string{}, *filenames)
if err == nil || !errors.IsNotFound(err) {
t.Errorf("unexpected error: expected NotFound, got %v", err)
}
}
func TestDeleteObjectIgnoreNotFound(t *testing.T) { func TestDeleteObjectIgnoreNotFound(t *testing.T) {
f, tf, codec := NewAPIFactory() f, tf, codec := NewAPIFactory()
tf.Printer = &testPrinter{} tf.Printer = &testPrinter{}
@ -141,6 +172,7 @@ func TestDeleteObjectIgnoreNotFound(t *testing.T) {
cmd := NewCmdDelete(f, buf) cmd := NewCmdDelete(f, buf)
cmd.Flags().Set("filename", "../../../examples/guestbook/redis-master-controller.json") cmd.Flags().Set("filename", "../../../examples/guestbook/redis-master-controller.json")
cmd.Flags().Set("cascade", "false") cmd.Flags().Set("cascade", "false")
cmd.Flags().Set("ignore-not-found", "true")
cmd.Run(cmd, []string{}) cmd.Run(cmd, []string{})
if buf.String() != "" { if buf.String() != "" {
@ -181,7 +213,7 @@ func TestDeleteMultipleObject(t *testing.T) {
} }
} }
func TestDeleteMultipleObjectIgnoreMissing(t *testing.T) { func TestDeleteMultipleObjectContinueOnMissing(t *testing.T) {
_, svc, _ := testData() _, svc, _ := testData()
f, tf, codec := NewAPIFactory() f, tf, codec := NewAPIFactory()
@ -207,7 +239,12 @@ func TestDeleteMultipleObjectIgnoreMissing(t *testing.T) {
cmd.Flags().Set("filename", "../../../examples/guestbook/redis-master-controller.json") cmd.Flags().Set("filename", "../../../examples/guestbook/redis-master-controller.json")
cmd.Flags().Set("filename", "../../../examples/guestbook/frontend-service.json") cmd.Flags().Set("filename", "../../../examples/guestbook/frontend-service.json")
cmd.Flags().Set("cascade", "false") cmd.Flags().Set("cascade", "false")
cmd.Run(cmd, []string{}) filenames := cmd.Flags().Lookup("filename").Value.(*util.StringList)
fmt.Printf("filenames: %v\n", filenames)
err := RunDelete(f, buf, cmd, []string{}, *filenames)
if err == nil || !errors.IsNotFound(err) {
t.Errorf("unexpected error: expected NotFound, got %v", err)
}
if buf.String() != "services/frontend\n" { if buf.String() != "services/frontend\n" {
t.Errorf("unexpected output: %s", buf.String()) t.Errorf("unexpected output: %s", buf.String())

View File

@ -57,10 +57,11 @@ func NewCmdStop(f *cmdutil.Factory, out io.Writer) *cobra.Command {
cmdutil.CheckErr(RunStop(f, cmd, args, flags.Filenames, out)) cmdutil.CheckErr(RunStop(f, cmd, args, flags.Filenames, out))
}, },
} }
usage := "Filename, directory, or URL to file of resource(s) to be stopped" usage := "Filename, directory, or URL to file of resource(s) to be stopped."
kubectl.AddJsonFilenameFlag(cmd, &flags.Filenames, usage) kubectl.AddJsonFilenameFlag(cmd, &flags.Filenames, usage)
cmd.Flags().StringP("selector", "l", "", "Selector (label query) to filter on") cmd.Flags().StringP("selector", "l", "", "Selector (label query) to filter on.")
cmd.Flags().Bool("all", false, "[-all] to select all the specified resources") cmd.Flags().Bool("all", false, "[-all] to select all the specified resources.")
cmd.Flags().Bool("ignore-not-found", false, "Treat \"resource not found\" as a successful stop.")
cmd.Flags().Int("grace-period", -1, "Period of time in seconds given to the resource to terminate gracefully. Ignored if negative.") cmd.Flags().Int("grace-period", -1, "Period of time in seconds given to the resource to terminate gracefully. Ignored if negative.")
return cmd return cmd
} }
@ -83,5 +84,5 @@ func RunStop(f *cmdutil.Factory, cmd *cobra.Command, args []string, filenames ut
if r.Err() != nil { if r.Err() != nil {
return r.Err() return r.Err()
} }
return ReapResult(r, f, out, false, cmdutil.GetFlagInt(cmd, "grace-period")) return ReapResult(r, f, out, false, cmdutil.GetFlagBool(cmd, "ignore-not-found"), cmdutil.GetFlagInt(cmd, "grace-period"))
} }