2014-10-05 21:24:19 -04:00
/ *
2016-06-02 20:25:58 -04:00
Copyright 2014 The Kubernetes Authors .
2014-10-05 21:24:19 -04: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-26 22:21:31 -04:00
"fmt"
2014-10-05 21:24:19 -04:00
"io"
2015-07-15 08:10:47 -04:00
"io/ioutil"
2015-06-27 00:25:08 -04:00
"os"
2015-07-15 08:10:47 -04:00
"path/filepath"
2014-10-05 21:24:19 -04:00
2015-04-11 02:06:05 -04:00
"github.com/spf13/cobra"
2015-08-05 18:05:17 -04:00
"github.com/golang/glog"
2017-01-13 12:48:50 -05:00
"k8s.io/apimachinery/pkg/api/errors"
2017-01-11 09:09:48 -05:00
"k8s.io/apimachinery/pkg/util/wait"
2015-08-05 18:03:47 -04:00
"k8s.io/kubernetes/pkg/kubectl"
2016-10-07 18:24:42 -04:00
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
2015-08-05 18:03:47 -04:00
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/resource"
2017-07-07 00:04:11 -04:00
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
2014-10-05 21:24:19 -04:00
)
2016-05-20 13:49:56 -04:00
var (
2017-02-15 22:47:00 -05:00
replaceLong = templates . LongDesc ( i18n . T ( `
2016-05-20 13:49:56 -04:00
Replace a resource by filename or stdin .
2015-02-20 16:28:43 -05:00
2016-05-20 13:49:56 -04:00
JSON and YAML formats are accepted . If replacing an existing resource , the
complete resource spec must be provided . This can be obtained by
2016-10-07 18:24:42 -04:00
$ kubectl get TYPE NAME - o yaml
2015-07-13 16:46:51 -04:00
2017-03-14 23:49:10 -04:00
Please refer to the models in https : //htmlpreview.github.io/?https://github.com/kubernetes/kubernetes/blob/HEAD/docs/api-reference/v1/definitions.html to find if a field is mutable.`))
2016-10-07 18:24:42 -04:00
2017-02-15 22:47:00 -05:00
replaceExample = templates . Examples ( i18n . T ( `
2016-05-20 13:49:56 -04:00
# Replace a pod using the data in pod . json .
kubectl replace - f . / pod . json
2015-02-20 16:28:43 -05:00
2016-05-20 13:49:56 -04:00
# Replace a pod based on the JSON passed into stdin .
cat pod . json | kubectl replace - f -
2015-06-17 19:56:55 -04:00
2016-05-20 13:49:56 -04:00
# Update a single - container pod ' s image version ( tag ) to v4
kubectl get pod mypod - o yaml | sed ' s / \ ( image : myimage \ ) : . * $ / \ 1 : v4 / ' | kubectl replace - f -
2015-08-07 18:21:31 -04:00
2016-05-20 13:49:56 -04:00
# Force replace , delete and then re - create the resource
2017-03-14 23:49:10 -04:00
kubectl replace -- force - f . / pod . json ` ) )
2015-02-20 16:28:43 -05:00
)
2016-10-12 20:18:39 -04:00
func NewCmdReplace ( f cmdutil . Factory , out io . Writer ) * cobra . Command {
2016-08-17 14:28:07 -04:00
options := & resource . FilenameOptions { }
2015-08-14 14:46:43 -04:00
2014-10-05 21:24:19 -04:00
cmd := & cobra . Command {
2017-05-18 18:34:04 -04:00
Use : "replace -f FILENAME" ,
2017-01-24 20:00:32 -05:00
Short : i18n . T ( "Replace a resource by filename or stdin" ) ,
2017-02-15 22:47:00 -05:00
Long : replaceLong ,
Example : replaceExample ,
2014-10-05 21:24:19 -04:00
Run : func ( cmd * cobra . Command , args [ ] string ) {
2015-07-01 18:47:43 -04:00
cmdutil . CheckErr ( cmdutil . ValidateOutputArgs ( cmd ) )
2015-08-14 14:46:43 -04:00
err := RunReplace ( f , out , cmd , args , options )
2015-07-31 19:43:39 -04:00
cmdutil . CheckErr ( err )
2014-10-05 21:24:19 -04:00
} ,
}
2016-08-17 14:28:07 -04:00
usage := "to use to replace the resource."
cmdutil . AddFilenameOptionFlags ( cmd , options , usage )
2015-03-17 11:49:35 -04:00
cmd . MarkFlagRequired ( "filename" )
2015-06-24 20:33:46 -04:00
cmd . Flags ( ) . Bool ( "force" , false , "Delete and re-create the specified resource" )
2015-08-10 12:03:43 -04:00
cmd . Flags ( ) . Bool ( "cascade" , false , "Only relevant during a force replace. If true, cascade the deletion of the resources managed by this resource (e.g. Pods created by a ReplicationController)." )
2015-06-27 00:25:08 -04:00
cmd . Flags ( ) . Int ( "grace-period" , - 1 , "Only relevant during a force replace. Period of time in seconds given to the old resource to terminate gracefully. Ignored if negative." )
2016-08-03 16:36:51 -04:00
cmd . Flags ( ) . Duration ( "timeout" , 0 , "Only relevant during a force replace. The length of time to wait before giving up on a delete of the old resource, zero means determine a timeout from the size of the object. Any other values should contain a corresponding time unit (e.g. 1s, 2m, 3h)." )
2015-09-10 17:58:09 -04:00
cmdutil . AddValidateFlags ( cmd )
2015-07-01 18:47:43 -04:00
cmdutil . AddOutputFlagsForMutation ( cmd )
2015-11-04 16:47:08 -05:00
cmdutil . AddApplyAnnotationFlags ( cmd )
2016-01-22 13:33:23 -05:00
cmdutil . AddRecordFlag ( cmd )
2016-03-09 20:27:19 -05:00
cmdutil . AddInclude3rdPartyFlags ( cmd )
2014-10-05 21:24:19 -04:00
return cmd
}
2015-01-15 16:55:53 -05:00
2016-10-12 20:18:39 -04:00
func RunReplace ( f cmdutil . Factory , out io . Writer , cmd * cobra . Command , args [ ] string , options * resource . FilenameOptions ) error {
2017-09-28 18:39:17 -04:00
schema , err := f . Validator ( cmdutil . GetFlagBool ( cmd , "validate" ) )
2015-03-09 18:08:16 -04:00
if err != nil {
return err
}
2015-06-26 16:49:34 -04:00
cmdNamespace , enforceNamespace , err := f . DefaultNamespace ( )
2015-03-09 18:08:16 -04:00
if err != nil {
return err
}
2015-06-24 20:33:46 -04:00
force := cmdutil . GetFlagBool ( cmd , "force" )
2017-06-14 17:14:42 -04:00
if cmdutil . IsFilenameSliceEmpty ( options . Filenames ) {
return cmdutil . UsageErrorf ( cmd , "Must specify --filename to replace" )
2015-03-09 18:08:16 -04:00
}
2015-08-05 10:21:47 -04:00
shortOutput := cmdutil . GetFlagString ( cmd , "output" ) == "name"
2015-06-24 20:33:46 -04:00
if force {
2015-08-14 14:46:43 -04:00
return forceReplace ( f , out , cmd , args , shortOutput , options )
2015-06-24 20:33:46 -04:00
}
2016-08-31 14:48:47 -04:00
if cmdutil . GetFlagInt ( cmd , "grace-period" ) >= 0 {
return fmt . Errorf ( "--grace-period must have --force specified" )
}
if cmdutil . GetFlagDuration ( cmd , "timeout" ) != 0 {
return fmt . Errorf ( "--timeout must have --force specified" )
}
2017-11-13 22:43:58 -05:00
r := f . NewBuilder ( ) .
2017-11-13 23:01:51 -05:00
Unstructured ( ) .
2015-05-07 16:53:43 -04:00
Schema ( schema ) .
2015-03-09 18:08:16 -04:00
ContinueOnError ( ) .
2015-06-26 16:49:34 -04:00
NamespaceParam ( cmdNamespace ) . DefaultNamespace ( ) .
2016-08-17 14:28:07 -04:00
FilenameParam ( enforceNamespace , options ) .
2015-03-09 18:08:16 -04:00
Flatten ( ) .
Do ( )
2017-11-13 23:01:51 -05:00
if err := r . Err ( ) ; err != nil {
2015-03-09 18:08:16 -04:00
return err
}
2017-11-13 23:01:51 -05:00
mapper := r . Mapper ( ) . RESTMapper
2015-06-14 22:48:56 -04:00
return r . Visit ( func ( info * resource . Info , err error ) error {
if err != nil {
return err
}
2015-09-10 17:32:57 -04:00
2015-12-21 00:37:49 -05:00
if err := kubectl . CreateOrUpdateAnnotation ( cmdutil . GetFlagBool ( cmd , cmdutil . ApplyAnnotationsFlag ) , info , f . JSONEncoder ( ) ) ; err != nil {
2015-11-04 16:47:08 -05:00
return cmdutil . AddSourceToErr ( "replacing" , info . Source , err )
2015-09-10 17:32:57 -04:00
}
2016-01-22 13:33:23 -05:00
if cmdutil . ShouldRecord ( cmd , info ) {
2017-02-25 10:40:50 -05:00
if err := cmdutil . RecordChangeCause ( info . Object , f . Command ( cmd , false ) ) ; err != nil {
2016-01-22 13:33:23 -05:00
return cmdutil . AddSourceToErr ( "replacing" , info . Source , err )
}
}
2015-09-10 17:32:57 -04:00
// Serialize the object with the annotation applied.
2015-10-28 12:43:21 -04:00
obj , err := resource . NewHelper ( info . Client , info . Mapping ) . Replace ( info . Namespace , info . Name , true , info . Object )
2015-03-09 18:08:16 -04:00
if err != nil {
2015-06-27 00:25:08 -04:00
return cmdutil . AddSourceToErr ( "replacing" , info . Source , err )
2015-03-09 18:08:16 -04:00
}
2015-09-10 17:32:57 -04:00
2015-03-09 18:08:16 -04:00
info . Refresh ( obj , true )
2016-05-24 08:56:12 -04:00
f . PrintObjectSpecificMessage ( obj , out )
2017-10-31 11:58:38 -04:00
f . PrintSuccess ( mapper , shortOutput , out , info . Mapping . Resource , info . Name , false , "replaced" )
2015-03-09 18:08:16 -04:00
return nil
} )
}
2016-10-12 20:18:39 -04:00
func forceReplace ( f cmdutil . Factory , out io . Writer , cmd * cobra . Command , args [ ] string , shortOutput bool , options * resource . FilenameOptions ) error {
2017-09-28 18:39:17 -04:00
schema , err := f . Validator ( cmdutil . GetFlagBool ( cmd , "validate" ) )
2015-06-24 20:33:46 -04:00
if err != nil {
return err
}
2015-06-26 16:49:34 -04:00
cmdNamespace , enforceNamespace , err := f . DefaultNamespace ( )
2015-06-24 20:33:46 -04:00
if err != nil {
return err
}
2015-08-14 14:46:43 -04:00
for i , filename := range options . Filenames {
2015-07-15 08:10:47 -04:00
if filename == "-" {
tempDir , err := ioutil . TempDir ( "" , "kubectl_replace_" )
if err != nil {
return err
}
defer os . RemoveAll ( tempDir )
tempFilename := filepath . Join ( tempDir , "resource.stdin" )
err = cmdutil . DumpReaderToFile ( os . Stdin , tempFilename )
if err != nil {
return err
}
2015-08-14 14:46:43 -04:00
options . Filenames [ i ] = tempFilename
2015-07-15 08:10:47 -04:00
}
}
2017-11-15 01:10:30 -05:00
r := f . NewBuilder ( ) .
Unstructured ( ) .
2015-06-24 20:33:46 -04:00
ContinueOnError ( ) .
NamespaceParam ( cmdNamespace ) . DefaultNamespace ( ) .
2016-08-17 14:28:07 -04:00
FilenameParam ( enforceNamespace , options ) .
2015-06-24 20:33:46 -04:00
ResourceTypeOrNameArgs ( false , args ... ) . RequireObject ( false ) .
Flatten ( ) .
Do ( )
2017-11-13 23:01:51 -05:00
if err := r . Err ( ) ; err != nil {
2015-06-24 20:33:46 -04:00
return err
}
2017-11-13 23:01:51 -05:00
mapper := r . Mapper ( ) . RESTMapper
2015-06-27 00:25:08 -04:00
//Replace will create a resource if it doesn't exist already, so ignore not found error
2015-06-24 20:33:46 -04:00
ignoreNotFound := true
2016-08-31 20:12:19 -04:00
timeout := cmdutil . GetFlagDuration ( cmd , "timeout" )
2016-11-21 22:22:24 -05:00
gracePeriod := cmdutil . GetFlagInt ( cmd , "grace-period" )
waitForDeletion := false
if gracePeriod == 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.
gracePeriod = 1
waitForDeletion = true
}
2015-06-24 20:33:46 -04:00
// By default use a reaper to delete all related resources.
if cmdutil . GetFlagBool ( cmd , "cascade" ) {
glog . Warningf ( "\"cascade\" is set, kubectl will delete and re-create all resources managed by this resource (e.g. Pods created by a ReplicationController). Consider using \"kubectl rolling-update\" if you want to update a ReplicationController together with its Pods." )
2016-11-21 22:22:24 -05:00
err = ReapResult ( r , f , out , cmdutil . GetFlagBool ( cmd , "cascade" ) , ignoreNotFound , timeout , gracePeriod , waitForDeletion , shortOutput , mapper , false )
2015-06-24 20:33:46 -04:00
} else {
2017-10-31 11:58:38 -04:00
err = DeleteResult ( r , f , out , ignoreNotFound , gracePeriod , shortOutput , mapper )
2015-06-24 20:33:46 -04:00
}
if err != nil {
return err
}
2016-08-31 20:12:19 -04:00
if timeout == 0 {
timeout = kubectl . Timeout
}
2017-11-02 08:15:34 -04:00
err = r . Visit ( func ( info * resource . Info , err error ) error {
2016-08-31 20:12:19 -04:00
if err != nil {
return err
}
return wait . PollImmediate ( kubectl . Interval , timeout , func ( ) ( bool , error ) {
if err := info . Get ( ) ; ! errors . IsNotFound ( err ) {
return false , err
}
return true , nil
} )
} )
2017-11-02 08:15:34 -04:00
if err != nil {
return err
}
2016-08-31 20:12:19 -04:00
2017-11-13 22:43:58 -05:00
r = f . NewBuilder ( ) .
2017-11-13 23:01:51 -05:00
Unstructured ( ) .
2015-06-24 20:33:46 -04:00
Schema ( schema ) .
ContinueOnError ( ) .
2015-06-26 16:49:34 -04:00
NamespaceParam ( cmdNamespace ) . DefaultNamespace ( ) .
2016-08-17 14:28:07 -04:00
FilenameParam ( enforceNamespace , options ) .
2015-06-24 20:33:46 -04:00
Flatten ( ) .
Do ( )
err = r . Err ( )
if err != nil {
return err
}
count := 0
2015-06-14 22:48:56 -04:00
err = r . Visit ( func ( info * resource . Info , err error ) error {
if err != nil {
return err
}
2015-09-10 17:32:57 -04:00
2015-12-21 00:37:49 -05:00
if err := kubectl . CreateOrUpdateAnnotation ( cmdutil . GetFlagBool ( cmd , cmdutil . ApplyAnnotationsFlag ) , info , f . JSONEncoder ( ) ) ; err != nil {
2015-09-10 17:32:57 -04:00
return err
}
2016-01-22 13:33:23 -05:00
if cmdutil . ShouldRecord ( cmd , info ) {
2017-02-25 10:40:50 -05:00
if err := cmdutil . RecordChangeCause ( info . Object , f . Command ( cmd , false ) ) ; err != nil {
2016-01-22 13:33:23 -05:00
return cmdutil . AddSourceToErr ( "replacing" , info . Source , err )
}
}
2015-10-28 12:43:21 -04:00
obj , err := resource . NewHelper ( info . Client , info . Mapping ) . Create ( info . Namespace , true , info . Object )
2015-06-24 20:33:46 -04:00
if err != nil {
return err
}
2015-09-10 17:32:57 -04:00
2015-06-24 20:33:46 -04:00
count ++
info . Refresh ( obj , true )
2016-05-24 08:56:12 -04:00
f . PrintObjectSpecificMessage ( obj , out )
2017-10-31 11:58:38 -04:00
f . PrintSuccess ( mapper , shortOutput , out , info . Mapping . Resource , info . Name , false , "replaced" )
2015-06-24 20:33:46 -04:00
return nil
} )
if err != nil {
return err
}
if count == 0 {
2015-06-27 00:25:08 -04:00
return fmt . Errorf ( "no objects passed to replace" )
2015-06-24 20:33:46 -04:00
}
return nil
}