2014-10-06 01:24:19 +00:00
/ *
2016-06-03 00:25:58 +00:00
Copyright 2014 The Kubernetes Authors .
2014-10-06 01:24:19 +00:00
Licensed under the Apache License , Version 2.0 ( the "License" ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an "AS IS" BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
* /
package cmd
import (
2014-10-27 02:21:31 +00:00
"fmt"
2014-10-06 01:24:19 +00:00
"io"
2015-05-29 23:16:30 +00:00
"time"
2014-10-06 01:24:19 +00:00
"github.com/spf13/cobra"
2014-12-15 17:32:46 +00:00
2017-01-13 17:48:50 +00:00
"k8s.io/apimachinery/pkg/api/errors"
2017-01-11 14:09:48 +00:00
"k8s.io/apimachinery/pkg/api/meta"
2017-01-24 15:38:21 +00:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2017-01-11 14:09:48 +00:00
"k8s.io/apimachinery/pkg/util/wait"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/kubectl"
2016-10-07 22:24:42 +00:00
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
2015-08-05 22:03:47 +00:00
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/resource"
2017-02-19 22:56:11 +00:00
"k8s.io/kubernetes/pkg/printers"
2017-01-25 01:00:32 +00:00
"k8s.io/kubernetes/pkg/util/i18n"
2014-10-06 01:24:19 +00:00
)
2016-05-20 17:49:56 +00:00
var (
2017-03-15 03:49:10 +00:00
delete_long = templates . LongDesc ( i18n . T ( `
2016-05-20 17:49:56 +00:00
Delete resources by filenames , stdin , resources and names , or by resources and label selector .
2014-10-06 01:24:19 +00:00
2016-10-25 02:43:37 +00:00
JSON and YAML formats are accepted . Only one type of the arguments may be specified : filenames ,
resources and names , or resources and label selector .
Some resources , such as pods , support graceful deletion . These resources define a default period
before they are forcibly terminated ( the grace period ) but you may override that value with
the -- grace - period flag , or pass -- now to set a grace - period of 1. Because these resources often
represent entities in the cluster , deletion may not be acknowledged immediately . If the node
hosting a pod is down or cannot reach the API server , termination may take significantly longer
than the grace period . To force delete a resource , you must pass a grace period of 0 and specify
the -- force flag .
IMPORTANT : Force deleting pods does not wait for confirmation that the pod ' s processes have been
terminated , which can leave those processes running until the node detects the deletion and
completes graceful deletion . If your processes use shared storage or talk to a remote API and
depend on the name of the pod to identify themselves , force deleting those pods may result in
multiple processes running on different machines using the same identification which may lead
to data corruption or inconsistency . Only force delete pods when you are sure the pod is
terminated , or if your application can tolerate multiple copies of the same pod running at once .
Also , if you force delete pods the scheduler may place new pods on those nodes before the node
has released those resources and causing those pods to be evicted immediately .
2014-10-06 01:24:19 +00:00
2016-05-20 17:49:56 +00:00
Note that the delete command does NOT do resource version checks , so if someone
submits an update to a resource right when you submit a delete , their update
2017-03-15 03:49:10 +00:00
will be lost along with the rest of the resource . ` ) )
2016-10-07 22:24:42 +00:00
2017-03-15 03:49:10 +00:00
delete_example = templates . Examples ( i18n . T ( `
2016-05-20 17:49:56 +00:00
# Delete a pod using the type and name specified in pod . json .
kubectl delete - f . / pod . json
2014-10-06 01:24:19 +00:00
2016-05-20 17:49:56 +00:00
# Delete a pod based on the type and name in the JSON passed into stdin .
cat pod . json | kubectl delete - f -
2014-12-15 17:32:46 +00:00
2016-05-20 17:49:56 +00:00
# Delete pods and services with same names "baz" and "foo"
kubectl delete pod , service baz foo
2015-08-19 08:33:02 +00:00
2016-05-20 17:49:56 +00:00
# Delete pods and services with label name = myLabel .
kubectl delete pods , services - l name = myLabel
2015-02-03 17:59:21 +00:00
2016-10-25 02:43:37 +00:00
# Delete a pod with minimal delay
2016-05-20 17:49:56 +00:00
kubectl delete pod foo -- now
2016-04-01 19:27:06 +00:00
2016-10-25 02:43:37 +00:00
# Force delete a pod on a dead node
kubectl delete pod foo -- grace - period = 0 -- force
2016-05-20 17:49:56 +00:00
# Delete all pods
2017-03-15 03:49:10 +00:00
kubectl delete pods -- all ` ) )
2015-02-20 21:28:43 +00:00
)
2015-02-12 14:59:58 +00:00
2017-01-15 07:30:06 +00:00
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
}
2016-11-22 03:22:24 +00:00
func NewCmdDelete ( f cmdutil . Factory , out , errOut io . Writer ) * cobra . Command {
2017-01-15 07:30:06 +00:00
options := & DeleteOptions { }
2015-08-14 18:46:43 +00:00
2015-09-02 22:38:40 +00:00
// retrieve a list of handled resources from printer as valid args
2016-03-20 18:14:25 +00:00
validArgs , argAliases := [ ] string { } , [ ] string { }
2017-02-19 22:56:11 +00:00
p , err := f . Printer ( nil , printers . PrintOptions {
2016-06-23 14:49:31 +00:00
ColumnLabels : [ ] string { } ,
} )
2015-09-02 22:38:40 +00:00
cmdutil . CheckErr ( err )
if p != nil {
validArgs = p . HandledResources ( )
2016-03-20 18:14:25 +00:00
argAliases = kubectl . ResourceAliases ( validArgs )
2015-09-02 22:38:40 +00:00
}
2015-02-20 21:28:43 +00:00
cmd := & cobra . Command {
2015-07-06 11:31:27 +00:00
Use : "delete ([-f FILENAME] | TYPE [(NAME | -l label | --all)])" ,
2017-01-25 01:00:32 +00:00
Short : i18n . T ( "Delete resources by filenames, stdin, resources and names, or by resources and label selector" ) ,
2015-02-20 21:28:43 +00:00
Long : delete_long ,
Example : delete_example ,
2014-10-06 01:24:19 +00:00
Run : func ( cmd * cobra . Command , args [ ] string ) {
2015-07-01 22:47:43 +00:00
cmdutil . CheckErr ( cmdutil . ValidateOutputArgs ( cmd ) )
2017-01-15 07:30:06 +00:00
if err := options . Complete ( f , out , errOut , args ) ; err != nil {
cmdutil . CheckErr ( err )
}
2017-03-17 13:55:46 +00:00
if err := options . Validate ( cmd ) ; err != nil {
2017-01-15 07:30:06 +00:00
cmdutil . CheckErr ( cmdutil . UsageError ( cmd , err . Error ( ) ) )
}
if err := options . RunDelete ( ) ; err != nil {
cmdutil . CheckErr ( err )
}
2014-10-06 01:24:19 +00:00
} ,
2016-05-05 00:18:52 +00:00
SuggestFor : [ ] string { "rm" } ,
2016-03-20 18:14:25 +00:00
ValidArgs : validArgs ,
ArgAliases : argAliases ,
2014-10-06 01:24:19 +00:00
}
2016-08-17 18:28:07 +00:00
usage := "containing the resource to delete."
2017-01-15 07:30:06 +00:00
cmdutil . AddFilenameOptionFlags ( cmd , & options . FilenameOptions , usage )
cmd . Flags ( ) . StringVarP ( & options . Selector , "selector" , "l" , "" , "Selector (label query) to filter on." )
2017-04-07 13:04:55 +00:00
cmd . Flags ( ) . BoolVar ( & options . DeleteAll , "all" , false , "select all resources in the namespace of the specified resource types." )
2017-01-15 07:30:06 +00:00
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 ( ) . 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 ( ) . IntVar ( & options . GracePeriod , "grace-period" , - 1 , "Period of time in seconds given to the resource to terminate gracefully. Ignored if negative." )
cmd . Flags ( ) . BoolVar ( & options . DeleteNow , "now" , false , "If true, resources are signaled for immediate shutdown (same as --grace-period=1)." )
cmd . Flags ( ) . BoolVar ( & options . ForceDeletion , "force" , false , "Immediate deletion of some resources may result in inconsistency or data loss and requires confirmation." )
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 . AddOutputVarFlagsForMutation ( cmd , & options . Output )
cmdutil . AddInclude3rdPartyVarFlags ( cmd , & options . Include3rdParty )
2014-10-06 01:24:19 +00:00
return cmd
}
2015-03-09 22:08:16 +00:00
2017-01-15 07:30:06 +00:00
func ( o * DeleteOptions ) Complete ( f cmdutil . Factory , out , errOut io . Writer , args [ ] string ) error {
2015-06-26 20:49:34 +00:00
cmdNamespace , enforceNamespace , err := f . DefaultNamespace ( )
2015-03-09 22:08:16 +00:00
if err != nil {
return err
}
2017-01-15 07:30:06 +00:00
// Set up client based support.
2017-05-16 21:52:51 +00:00
mapper , _ , err := f . UnstructuredObject ( )
2016-11-02 17:06:19 +00:00
if err != nil {
return err
}
2017-05-16 21:52:51 +00:00
builder , err := f . NewUnstructuredBuilder ( true )
if err != nil {
return err
}
2017-01-15 07:30:06 +00:00
o . Mapper = mapper
2017-05-16 21:52:51 +00:00
r := builder .
2015-03-09 22:08:16 +00:00
ContinueOnError ( ) .
NamespaceParam ( cmdNamespace ) . DefaultNamespace ( ) .
2017-01-15 07:30:06 +00:00
FilenameParam ( enforceNamespace , & o . FilenameOptions ) .
SelectorParam ( o . Selector ) .
SelectAllParam ( o . DeleteAll ) .
2015-04-20 19:00:52 +00:00
ResourceTypeOrNameArgs ( false , args ... ) . RequireObject ( false ) .
2015-03-09 22:08:16 +00:00
Flatten ( ) .
Do ( )
err = r . Err ( )
if err != nil {
return err
}
2017-01-15 07:30:06 +00:00
o . Result = r
o . f = f
// Set up writer
o . Out = out
o . ErrOut = errOut
2015-03-09 22:08:16 +00:00
2017-01-15 07:30:06 +00:00
return nil
}
2017-03-17 13:55:46 +00:00
func ( o * DeleteOptions ) Validate ( cmd * cobra . Command ) error {
2017-01-15 07:30:06 +00:00
if o . DeleteAll {
2015-07-07 17:32:05 +00:00
f := cmd . Flags ( ) . Lookup ( "ignore-not-found" )
// The flag should never be missing
if f == nil {
return fmt . Errorf ( "missing --ignore-not-found flag" )
}
// If the user didn't explicitly set the option, default to ignoring NotFound errors when used with --all
if ! f . Changed {
2017-01-15 07:30:06 +00:00
o . IgnoreNotFound = true
2015-07-07 17:32:05 +00:00
}
}
2017-01-15 07:30:06 +00:00
if o . DeleteNow {
if o . GracePeriod != - 1 {
2016-04-01 19:27:06 +00:00
return fmt . Errorf ( "--now and --grace-period cannot be specified together" )
}
2017-01-15 07:30:06 +00:00
o . GracePeriod = 1
2016-10-25 02:43:37 +00:00
}
2017-01-15 07:30:06 +00:00
if o . GracePeriod == 0 {
if o . ForceDeletion {
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" )
2016-11-22 03:22:24 +00:00
} 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.
2017-01-15 07:30:06 +00:00
o . WaitForDeletion = true
o . GracePeriod = 1
2016-11-22 03:22:24 +00:00
}
2016-04-01 19:27:06 +00:00
}
2017-01-15 07:30:06 +00:00
return nil
}
2016-04-01 19:27:06 +00:00
2017-01-15 07:30:06 +00:00
func ( o * DeleteOptions ) RunDelete ( ) error {
shortOutput := o . Output == "name"
2015-04-23 04:15:15 +00:00
// By default use a reaper to delete all related resources.
2017-01-15 07:30:06 +00:00
if o . Cascade {
return ReapResult ( o . Result , o . f , o . Out , true , o . IgnoreNotFound , o . Timeout , o . GracePeriod , o . WaitForDeletion , shortOutput , o . Mapper , false )
2015-04-23 04:15:15 +00:00
}
2017-01-15 07:30:06 +00:00
return DeleteResult ( o . Result , o . Out , o . IgnoreNotFound , shortOutput , o . Mapper )
2015-04-23 04:15:15 +00:00
}
2016-11-22 03:22:24 +00:00
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 {
2015-03-09 22:08:16 +00:00
found := 0
2015-05-21 17:01:34 +00:00
if ignoreNotFound {
r = r . IgnoreErrors ( errors . IsNotFound )
}
2015-06-15 02:48:56 +00:00
err := r . Visit ( func ( info * resource . Info , err error ) error {
if err != nil {
return err
}
2015-03-09 22:08:16 +00:00
found ++
2015-04-23 04:15:15 +00:00
reaper , err := f . Reaper ( info . Mapping )
if err != nil {
2015-05-21 17:01:34 +00:00
// If there is no reaper for this resources and the user didn't explicitly ask for stop.
2015-04-23 04:15:15 +00:00
if kubectl . IsNoSuchReaperError ( err ) && isDefaultDelete {
2017-01-27 03:15:59 +00:00
// No client side reaper found. Let the server do cascading deletion.
return cascadingDeleteResource ( info , out , shortOutput , mapper )
2015-04-23 04:15:15 +00:00
}
2015-06-23 12:26:27 +00:00
return cmdutil . AddSourceToErr ( "reaping" , info . Source , err )
2015-03-09 22:08:16 +00:00
}
2017-01-24 15:38:21 +00:00
var options * metav1 . DeleteOptions
2015-04-28 12:21:57 +00:00
if gracePeriod >= 0 {
2017-01-24 15:38:21 +00:00
options = metav1 . NewDeleteOptions ( int64 ( gracePeriod ) )
2015-04-28 12:21:57 +00:00
}
2015-11-12 14:42:29 +00:00
if err := reaper . Stop ( info . Namespace , info . Name , timeout , options ) ; err != nil {
2015-06-23 12:26:27 +00:00
return cmdutil . AddSourceToErr ( "stopping" , info . Source , err )
2015-04-23 04:15:15 +00:00
}
2016-11-22 03:22:24 +00:00
if waitForDeletion {
if err := waitForObjectDeletion ( info , timeout ) ; err != nil {
return cmdutil . AddSourceToErr ( "stopping" , info . Source , err )
}
}
2016-08-08 21:24:44 +00:00
if ! quiet {
2016-08-23 18:11:39 +00:00
cmdutil . PrintSuccess ( mapper , shortOutput , out , info . Mapping . Resource , info . Name , false , "deleted" )
2016-08-08 21:24:44 +00:00
}
2015-03-09 22:08:16 +00:00
return nil
} )
if err != nil {
return err
}
if found == 0 {
2015-04-23 04:15:15 +00:00
fmt . Fprintf ( out , "No resources found\n" )
}
return nil
}
2015-07-01 22:47:43 +00:00
func DeleteResult ( r * resource . Result , out io . Writer , ignoreNotFound bool , shortOutput bool , mapper meta . RESTMapper ) error {
2015-04-23 04:15:15 +00:00
found := 0
2015-05-21 17:01:34 +00:00
if ignoreNotFound {
r = r . IgnoreErrors ( errors . IsNotFound )
}
2015-06-15 02:48:56 +00:00
err := r . Visit ( func ( info * resource . Info , err error ) error {
if err != nil {
return err
}
2015-04-23 04:15:15 +00:00
found ++
2017-05-11 12:07:25 +00:00
// if we're here, it means that cascade=false (not the default), so we should orphan as requested
orphan := true
return deleteResource ( info , out , shortOutput , mapper , & metav1 . DeleteOptions { OrphanDependents : & orphan } )
2015-04-23 04:15:15 +00:00
} )
if err != nil {
return err
}
if found == 0 {
fmt . Fprintf ( out , "No resources found\n" )
}
return nil
}
2017-01-27 03:15:59 +00:00
func cascadingDeleteResource ( info * resource . Info , out io . Writer , shortOutput bool , mapper meta . RESTMapper ) error {
falseVar := false
deleteOptions := & metav1 . DeleteOptions { OrphanDependents : & falseVar }
return deleteResource ( info , out , shortOutput , mapper , deleteOptions )
}
func deleteResource ( info * resource . Info , out io . Writer , shortOutput bool , mapper meta . RESTMapper , deleteOptions * metav1 . DeleteOptions ) error {
if err := resource . NewHelper ( info . Client , info . Mapping ) . DeleteWithOptions ( info . Namespace , info . Name , deleteOptions ) ; err != nil {
2015-06-23 12:26:27 +00:00
return cmdutil . AddSourceToErr ( "deleting" , info . Source , err )
2015-03-09 22:08:16 +00:00
}
2016-08-23 18:11:39 +00:00
cmdutil . PrintSuccess ( mapper , shortOutput , out , info . Mapping . Resource , info . Name , false , "deleted" )
2015-03-09 22:08:16 +00:00
return nil
}
2016-11-22 03:22:24 +00:00
// 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
}
} )
}