mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-29 06:27:05 +00:00
refactor delete to remove cobra dependency
This commit is contained in:
parent
e73e749459
commit
d6d82425a4
@ -89,8 +89,33 @@ var (
|
|||||||
kubectl delete pods --all`)
|
kubectl delete pods --all`)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type DeleteOptions struct {
|
||||||
|
resource.FilenameOptions
|
||||||
|
|
||||||
|
Selector string
|
||||||
|
DeleteAll bool
|
||||||
|
IgnoreNotFound bool
|
||||||
|
Cascade bool
|
||||||
|
DeleteNow bool
|
||||||
|
ForceDeletion bool
|
||||||
|
WaitForDeletion bool
|
||||||
|
|
||||||
|
GracePeriod int
|
||||||
|
Timeout time.Duration
|
||||||
|
|
||||||
|
Include3rdParty bool
|
||||||
|
Output string
|
||||||
|
|
||||||
|
Mapper meta.RESTMapper
|
||||||
|
Result *resource.Result
|
||||||
|
|
||||||
|
f cmdutil.Factory
|
||||||
|
Out io.Writer
|
||||||
|
ErrOut io.Writer
|
||||||
|
}
|
||||||
|
|
||||||
func NewCmdDelete(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
func NewCmdDelete(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
||||||
options := &resource.FilenameOptions{}
|
options := &DeleteOptions{}
|
||||||
|
|
||||||
// retrieve a list of handled resources from printer as valid args
|
// retrieve a list of handled resources from printer as valid args
|
||||||
validArgs, argAliases := []string{}, []string{}
|
validArgs, argAliases := []string{}, []string{}
|
||||||
@ -110,44 +135,53 @@ func NewCmdDelete(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
|||||||
Example: delete_example,
|
Example: delete_example,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
cmdutil.CheckErr(cmdutil.ValidateOutputArgs(cmd))
|
cmdutil.CheckErr(cmdutil.ValidateOutputArgs(cmd))
|
||||||
err := RunDelete(f, out, errOut, cmd, args, options)
|
if err := options.Complete(f, out, errOut, args); err != nil {
|
||||||
cmdutil.CheckErr(err)
|
cmdutil.CheckErr(err)
|
||||||
|
}
|
||||||
|
if err := options.Validate(f, cmd); err != nil {
|
||||||
|
cmdutil.CheckErr(cmdutil.UsageError(cmd, err.Error()))
|
||||||
|
}
|
||||||
|
if err := options.RunDelete(); err != nil {
|
||||||
|
cmdutil.CheckErr(err)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
SuggestFor: []string{"rm"},
|
SuggestFor: []string{"rm"},
|
||||||
ValidArgs: validArgs,
|
ValidArgs: validArgs,
|
||||||
ArgAliases: argAliases,
|
ArgAliases: argAliases,
|
||||||
}
|
}
|
||||||
usage := "containing the resource to delete."
|
usage := "containing the resource to delete."
|
||||||
cmdutil.AddFilenameOptionFlags(cmd, options, usage)
|
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
|
||||||
cmd.Flags().StringP("selector", "l", "", "Selector (label query) to filter on.")
|
cmd.Flags().StringVarP(&options.Selector, "selector", "l", "", "Selector (label query) to filter on.")
|
||||||
cmd.Flags().Bool("all", false, "[-all] to select all the specified resources.")
|
cmd.Flags().BoolVar(&options.DeleteAll, "all", false, "[-all] to select all the specified resources.")
|
||||||
cmd.Flags().Bool("ignore-not-found", false, "Treat \"resource not found\" as a successful delete. Defaults to \"true\" when --all is specified.")
|
cmd.Flags().BoolVar(&options.IgnoreNotFound, "ignore-not-found", false, "Treat \"resource not found\" as a successful delete. Defaults to \"true\" when --all is specified.")
|
||||||
cmd.Flags().Bool("cascade", true, "If true, cascade the deletion of the resources managed by this resource (e.g. Pods created by a ReplicationController). Default true.")
|
cmd.Flags().BoolVar(&options.Cascade, "cascade", true, "If true, cascade the deletion of the 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().IntVar(&options.GracePeriod, "grace-period", -1, "Period of time in seconds given to the resource to terminate gracefully. Ignored if negative.")
|
||||||
cmd.Flags().Bool("now", false, "If true, resources are signaled for immediate shutdown (same as --grace-period=1).")
|
cmd.Flags().BoolVar(&options.DeleteNow, "now", false, "If true, resources are signaled for immediate shutdown (same as --grace-period=1).")
|
||||||
cmd.Flags().Bool("force", false, "Immediate deletion of some resources may result in inconsistency or data loss and requires confirmation.")
|
cmd.Flags().BoolVar(&options.ForceDeletion, "force", false, "Immediate deletion of some resources may result in inconsistency or data loss and requires confirmation.")
|
||||||
cmd.Flags().Duration("timeout", 0, "The length of time to wait before giving up on a delete, zero means determine a timeout from the size of the object")
|
cmd.Flags().DurationVar(&options.Timeout, "timeout", 0, "The length of time to wait before giving up on a delete, zero means determine a timeout from the size of the object")
|
||||||
cmdutil.AddOutputFlagsForMutation(cmd)
|
cmdutil.AddOutputVarFlagsForMutation(cmd, &options.Output)
|
||||||
cmdutil.AddInclude3rdPartyFlags(cmd)
|
cmdutil.AddInclude3rdPartyVarFlags(cmd, &options.Include3rdParty)
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunDelete(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args []string, options *resource.FilenameOptions) error {
|
func (o *DeleteOptions) Complete(f cmdutil.Factory, out, errOut io.Writer, args []string) error {
|
||||||
cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
|
cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
deleteAll := cmdutil.GetFlagBool(cmd, "all")
|
|
||||||
|
// Set up client based support.
|
||||||
mapper, typer, err := f.UnstructuredObject()
|
mapper, typer, err := f.UnstructuredObject()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
o.Mapper = mapper
|
||||||
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
|
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
|
||||||
ContinueOnError().
|
ContinueOnError().
|
||||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||||
FilenameParam(enforceNamespace, options).
|
FilenameParam(enforceNamespace, &o.FilenameOptions).
|
||||||
SelectorParam(cmdutil.GetFlagString(cmd, "selector")).
|
SelectorParam(o.Selector).
|
||||||
SelectAllParam(deleteAll).
|
SelectAllParam(o.DeleteAll).
|
||||||
ResourceTypeOrNameArgs(false, args...).RequireObject(false).
|
ResourceTypeOrNameArgs(false, args...).RequireObject(false).
|
||||||
Flatten().
|
Flatten().
|
||||||
Do()
|
Do()
|
||||||
@ -155,9 +189,18 @@ func RunDelete(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, arg
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
o.Result = r
|
||||||
|
|
||||||
ignoreNotFound := cmdutil.GetFlagBool(cmd, "ignore-not-found")
|
o.f = f
|
||||||
if deleteAll {
|
// Set up writer
|
||||||
|
o.Out = out
|
||||||
|
o.ErrOut = errOut
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *DeleteOptions) Validate(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||||
|
if o.DeleteAll {
|
||||||
f := cmd.Flags().Lookup("ignore-not-found")
|
f := cmd.Flags().Lookup("ignore-not-found")
|
||||||
// The flag should never be missing
|
// The flag should never be missing
|
||||||
if f == nil {
|
if f == nil {
|
||||||
@ -165,37 +208,36 @@ func RunDelete(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, arg
|
|||||||
}
|
}
|
||||||
// If the user didn't explicitly set the option, default to ignoring NotFound errors when used with --all
|
// If the user didn't explicitly set the option, default to ignoring NotFound errors when used with --all
|
||||||
if !f.Changed {
|
if !f.Changed {
|
||||||
ignoreNotFound = true
|
o.IgnoreNotFound = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if o.DeleteNow {
|
||||||
gracePeriod := cmdutil.GetFlagInt(cmd, "grace-period")
|
if o.GracePeriod != -1 {
|
||||||
force := cmdutil.GetFlagBool(cmd, "force")
|
|
||||||
if cmdutil.GetFlagBool(cmd, "now") {
|
|
||||||
if gracePeriod != -1 {
|
|
||||||
return fmt.Errorf("--now and --grace-period cannot be specified together")
|
return fmt.Errorf("--now and --grace-period cannot be specified together")
|
||||||
}
|
}
|
||||||
gracePeriod = 1
|
o.GracePeriod = 1
|
||||||
}
|
}
|
||||||
wait := false
|
if o.GracePeriod == 0 {
|
||||||
if gracePeriod == 0 {
|
if o.ForceDeletion {
|
||||||
if force {
|
fmt.Fprintf(o.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")
|
||||||
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 {
|
} else {
|
||||||
// To preserve backwards compatibility, but prevent accidental data loss, we convert --grace-period=0
|
// 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
|
// into --grace-period=1 and wait until the object is successfully deleted. Users may provide --force
|
||||||
// to bypass this wait.
|
// to bypass this wait.
|
||||||
wait = true
|
o.WaitForDeletion = true
|
||||||
gracePeriod = 1
|
o.GracePeriod = 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
shortOutput := cmdutil.GetFlagString(cmd, "output") == "name"
|
func (o *DeleteOptions) RunDelete() error {
|
||||||
|
shortOutput := o.Output == "name"
|
||||||
// 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 o.Cascade {
|
||||||
return ReapResult(r, f, out, cmdutil.GetFlagBool(cmd, "cascade"), ignoreNotFound, cmdutil.GetFlagDuration(cmd, "timeout"), gracePeriod, wait, shortOutput, mapper, false)
|
return ReapResult(o.Result, o.f, o.Out, true, o.IgnoreNotFound, o.Timeout, o.GracePeriod, o.WaitForDeletion, shortOutput, o.Mapper, false)
|
||||||
}
|
}
|
||||||
return DeleteResult(r, out, ignoreNotFound, shortOutput, mapper)
|
return DeleteResult(o.Result, o.Out, o.IgnoreNotFound, shortOutput, o.Mapper)
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
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 {
|
||||||
|
@ -227,12 +227,19 @@ func TestDeleteObjectNotFound(t *testing.T) {
|
|||||||
tf.Namespace = "test"
|
tf.Namespace = "test"
|
||||||
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||||
|
|
||||||
cmd := NewCmdDelete(f, buf, errBuf)
|
options := &DeleteOptions{
|
||||||
options := &resource.FilenameOptions{}
|
FilenameOptions: resource.FilenameOptions{
|
||||||
options.Filenames = []string{"../../../examples/guestbook/legacy/redis-master-controller.yaml"}
|
Filenames: []string{"../../../examples/guestbook/legacy/redis-master-controller.yaml"},
|
||||||
cmd.Flags().Set("cascade", "false")
|
},
|
||||||
cmd.Flags().Set("output", "name")
|
GracePeriod: -1,
|
||||||
err := RunDelete(f, buf, errBuf, cmd, []string{}, options)
|
Cascade: false,
|
||||||
|
Output: "name",
|
||||||
|
}
|
||||||
|
err := options.Complete(f, buf, errBuf, []string{})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
err = options.RunDelete()
|
||||||
if err == nil || !errors.IsNotFound(err) {
|
if err == nil || !errors.IsNotFound(err) {
|
||||||
t.Errorf("unexpected error: expected NotFound, got %v", err)
|
t.Errorf("unexpected error: expected NotFound, got %v", err)
|
||||||
}
|
}
|
||||||
@ -296,14 +303,20 @@ func TestDeleteAllNotFound(t *testing.T) {
|
|||||||
tf.Namespace = "test"
|
tf.Namespace = "test"
|
||||||
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||||
|
|
||||||
cmd := NewCmdDelete(f, buf, errBuf)
|
|
||||||
cmd.Flags().Set("all", "true")
|
|
||||||
cmd.Flags().Set("cascade", "false")
|
|
||||||
// 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
|
||||||
cmd.Flags().Set("ignore-not-found", "false")
|
options := &DeleteOptions{
|
||||||
cmd.Flags().Set("output", "name")
|
FilenameOptions: resource.FilenameOptions{},
|
||||||
|
GracePeriod: -1,
|
||||||
err := RunDelete(f, buf, errBuf, cmd, []string{"services"}, &resource.FilenameOptions{})
|
Cascade: false,
|
||||||
|
DeleteAll: true,
|
||||||
|
IgnoreNotFound: false,
|
||||||
|
Output: "name",
|
||||||
|
}
|
||||||
|
err := options.Complete(f, buf, errBuf, []string{"services"})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
err = options.RunDelete()
|
||||||
if err == nil || !errors.IsNotFound(err) {
|
if err == nil || !errors.IsNotFound(err) {
|
||||||
t.Errorf("unexpected error: expected NotFound, got %v", err)
|
t.Errorf("unexpected error: expected NotFound, got %v", err)
|
||||||
}
|
}
|
||||||
@ -405,12 +418,19 @@ func TestDeleteMultipleObjectContinueOnMissing(t *testing.T) {
|
|||||||
tf.Namespace = "test"
|
tf.Namespace = "test"
|
||||||
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||||
|
|
||||||
cmd := NewCmdDelete(f, buf, errBuf)
|
options := &DeleteOptions{
|
||||||
options := &resource.FilenameOptions{}
|
FilenameOptions: resource.FilenameOptions{
|
||||||
options.Filenames = []string{"../../../examples/guestbook/legacy/redis-master-controller.yaml", "../../../examples/guestbook/frontend-service.yaml"}
|
Filenames: []string{"../../../examples/guestbook/legacy/redis-master-controller.yaml", "../../../examples/guestbook/frontend-service.yaml"},
|
||||||
cmd.Flags().Set("cascade", "false")
|
},
|
||||||
cmd.Flags().Set("output", "name")
|
GracePeriod: -1,
|
||||||
err := RunDelete(f, buf, errBuf, cmd, []string{}, options)
|
Cascade: false,
|
||||||
|
Output: "name",
|
||||||
|
}
|
||||||
|
err := options.Complete(f, buf, errBuf, []string{})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
err = options.RunDelete()
|
||||||
if err == nil || !errors.IsNotFound(err) {
|
if err == nil || !errors.IsNotFound(err) {
|
||||||
t.Errorf("unexpected error: expected NotFound, got %v", err)
|
t.Errorf("unexpected error: expected NotFound, got %v", err)
|
||||||
}
|
}
|
||||||
@ -533,7 +553,6 @@ func TestDeleteMultipleSelector(t *testing.T) {
|
|||||||
func TestResourceErrors(t *testing.T) {
|
func TestResourceErrors(t *testing.T) {
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
args []string
|
args []string
|
||||||
flags map[string]string
|
|
||||||
errFn func(error) bool
|
errFn func(error) bool
|
||||||
}{
|
}{
|
||||||
"no args": {
|
"no args": {
|
||||||
@ -562,17 +581,18 @@ func TestResourceErrors(t *testing.T) {
|
|||||||
|
|
||||||
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||||
|
|
||||||
cmd := NewCmdDelete(f, buf, errBuf)
|
options := &DeleteOptions{
|
||||||
cmd.SetOutput(buf)
|
FilenameOptions: resource.FilenameOptions{},
|
||||||
|
GracePeriod: -1,
|
||||||
for k, v := range testCase.flags {
|
Cascade: false,
|
||||||
cmd.Flags().Set(k, v)
|
Output: "name",
|
||||||
}
|
}
|
||||||
err := RunDelete(f, buf, errBuf, cmd, testCase.args, &resource.FilenameOptions{})
|
err := options.Complete(f, buf, errBuf, testCase.args)
|
||||||
if !testCase.errFn(err) {
|
if !testCase.errFn(err) {
|
||||||
t.Errorf("%s: unexpected error: %v", k, err)
|
t.Errorf("%s: unexpected error: %v", k, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if tf.Printer.(*testPrinter).Objects != nil {
|
if tf.Printer.(*testPrinter).Objects != nil {
|
||||||
t.Errorf("unexpected print to default printer")
|
t.Errorf("unexpected print to default printer")
|
||||||
}
|
}
|
||||||
|
@ -557,6 +557,11 @@ func ShouldRecord(cmd *cobra.Command, info *resource.Info) bool {
|
|||||||
return GetRecordFlag(cmd) || (ContainsChangeCause(info) && !cmd.Flags().Changed("record"))
|
return GetRecordFlag(cmd) || (ContainsChangeCause(info) && !cmd.Flags().Changed("record"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func AddInclude3rdPartyVarFlags(cmd *cobra.Command, include3rdParty *bool) {
|
||||||
|
cmd.Flags().BoolVar(include3rdParty, "include-extended-apis", true, "If true, include definitions of new APIs via calls to the API server. [default true]")
|
||||||
|
cmd.Flags().MarkDeprecated("include-extended-apis", "No longer required.")
|
||||||
|
}
|
||||||
|
|
||||||
func AddInclude3rdPartyFlags(cmd *cobra.Command) {
|
func AddInclude3rdPartyFlags(cmd *cobra.Command) {
|
||||||
cmd.Flags().Bool("include-extended-apis", true, "If true, include definitions of new APIs via calls to the API server. [default true]")
|
cmd.Flags().Bool("include-extended-apis", true, "If true, include definitions of new APIs via calls to the API server. [default true]")
|
||||||
cmd.Flags().MarkDeprecated("include-extended-apis", "No longer required.")
|
cmd.Flags().MarkDeprecated("include-extended-apis", "No longer required.")
|
||||||
|
@ -46,6 +46,11 @@ func AddOutputFlagsForMutation(cmd *cobra.Command) {
|
|||||||
cmd.Flags().StringP("output", "o", "", "Output mode. Use \"-o name\" for shorter output (resource/name).")
|
cmd.Flags().StringP("output", "o", "", "Output mode. Use \"-o name\" for shorter output (resource/name).")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddOutputVarFlagsForMutation adds output related flags to a command. Used by mutations only.
|
||||||
|
func AddOutputVarFlagsForMutation(cmd *cobra.Command, output *string) {
|
||||||
|
cmd.Flags().StringVarP(output, "output", "o", "", "Output mode. Use \"-o name\" for shorter output (resource/name).")
|
||||||
|
}
|
||||||
|
|
||||||
// AddOutputFlags adds output related flags to a command.
|
// AddOutputFlags adds output related flags to a command.
|
||||||
func AddOutputFlags(cmd *cobra.Command) {
|
func AddOutputFlags(cmd *cobra.Command) {
|
||||||
cmd.Flags().StringP("output", "o", "", "Output format. One of: json|yaml|wide|name|custom-columns=...|custom-columns-file=...|go-template=...|go-template-file=...|jsonpath=...|jsonpath-file=... See custom columns [http://kubernetes.io/docs/user-guide/kubectl-overview/#custom-columns], golang template [http://golang.org/pkg/text/template/#pkg-overview] and jsonpath template [http://kubernetes.io/docs/user-guide/jsonpath].")
|
cmd.Flags().StringP("output", "o", "", "Output format. One of: json|yaml|wide|name|custom-columns=...|custom-columns-file=...|go-template=...|go-template-file=...|jsonpath=...|jsonpath-file=... See custom columns [http://kubernetes.io/docs/user-guide/kubectl-overview/#custom-columns], golang template [http://golang.org/pkg/text/template/#pkg-overview] and jsonpath template [http://kubernetes.io/docs/user-guide/jsonpath].")
|
||||||
|
Loading…
Reference in New Issue
Block a user