2017-02-16 08:21:19 +00:00
/ *
Copyright 2017 The Kubernetes Authors .
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 (
"bytes"
"fmt"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
2018-05-03 12:05:50 +00:00
"k8s.io/apimachinery/pkg/runtime"
2017-02-16 08:21:19 +00:00
"k8s.io/apimachinery/pkg/types"
"k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
2017-02-26 12:36:20 +00:00
"k8s.io/kubernetes/pkg/kubectl/cmd/util/editor"
2018-04-19 21:43:28 +00:00
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
2017-02-16 08:21:19 +00:00
"k8s.io/kubernetes/pkg/kubectl/resource"
2017-07-07 04:04:11 +00:00
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
2018-04-26 13:30:21 +00:00
"k8s.io/kubernetes/pkg/printers"
2017-02-16 08:21:19 +00:00
)
type SetLastAppliedOptions struct {
CreateAnnotation bool
2018-04-26 13:30:21 +00:00
PrintFlags * printers . PrintFlags
PrintObj printers . ResourcePrinterFunc
FilenameOptions resource . FilenameOptions
infoList [ ] * resource . Info
namespace string
enforceNamespace bool
dryRun bool
shortOutput bool
output string
patchBufferList [ ] PatchBuffer
builder * resource . Builder
unstructuredClientForMapping func ( mapping * meta . RESTMapping ) ( resource . RESTClient , error )
2018-04-18 15:20:33 +00:00
2018-04-19 21:43:28 +00:00
genericclioptions . IOStreams
2017-02-16 08:21:19 +00:00
}
2017-02-26 12:36:20 +00:00
type PatchBuffer struct {
Patch [ ] byte
PatchType types . PatchType
}
2017-02-16 08:21:19 +00:00
var (
2017-03-15 03:49:10 +00:00
applySetLastAppliedLong = templates . LongDesc ( i18n . T ( `
2017-02-16 08:21:19 +00:00
Set the latest last - applied - configuration annotations by setting it to match the contents of a file .
This results in the last - applied - configuration being updated as though ' kubectl apply - f < file > ' was run ,
2017-03-15 03:49:10 +00:00
without updating any other parts of the object . ` ) )
2017-02-16 08:21:19 +00:00
2017-03-15 03:49:10 +00:00
applySetLastAppliedExample = templates . Examples ( i18n . T ( `
2017-02-16 08:21:19 +00:00
# Set the last - applied - configuration of a resource to match the contents of a file .
kubectl apply set - last - applied - f deploy . yaml
# Execute set - last - applied against each configuration file in a directory .
kubectl apply set - last - applied - f path /
# Set the last - applied - configuration of a resource to match the contents of a file , will create the annotation if it does not already exist .
kubectl apply set - last - applied - f deploy . yaml -- create - annotation = true
2017-03-15 03:49:10 +00:00
` ) )
2017-02-16 08:21:19 +00:00
)
2018-04-19 21:43:28 +00:00
func NewSetLastAppliedOptions ( ioStreams genericclioptions . IOStreams ) * SetLastAppliedOptions {
2018-04-18 15:20:33 +00:00
return & SetLastAppliedOptions {
2018-04-26 13:30:21 +00:00
PrintFlags : printers . NewPrintFlags ( "configured" ) ,
IOStreams : ioStreams ,
2018-04-18 15:20:33 +00:00
}
}
2018-04-19 21:43:28 +00:00
func NewCmdApplySetLastApplied ( f cmdutil . Factory , ioStreams genericclioptions . IOStreams ) * cobra . Command {
2018-04-26 13:30:21 +00:00
o := NewSetLastAppliedOptions ( ioStreams )
2017-02-16 08:21:19 +00:00
cmd := & cobra . Command {
2017-10-11 06:26:02 +00:00
Use : "set-last-applied -f FILENAME" ,
DisableFlagsInUseLine : true ,
2017-03-15 03:49:10 +00:00
Short : i18n . T ( "Set the last-applied-configuration annotation on a live object to match the contents of a file." ) ,
2017-02-16 08:21:19 +00:00
Long : applySetLastAppliedLong ,
Example : applySetLastAppliedExample ,
Run : func ( cmd * cobra . Command , args [ ] string ) {
2018-04-26 13:30:21 +00:00
cmdutil . CheckErr ( o . Complete ( f , cmd ) )
cmdutil . CheckErr ( o . Validate ( ) )
cmdutil . CheckErr ( o . RunSetLastApplied ( ) )
2017-02-16 08:21:19 +00:00
} ,
}
cmdutil . AddDryRunFlag ( cmd )
cmdutil . AddPrinterFlags ( cmd )
2018-04-26 13:30:21 +00:00
cmd . Flags ( ) . BoolVar ( & o . CreateAnnotation , "create-annotation" , o . CreateAnnotation , "Will create 'last-applied-configuration' annotations if current objects doesn't have one" )
kubectl . AddJsonFilenameFlag ( cmd , & o . FilenameOptions . Filenames , "Filename, directory, or URL to files that contains the last-applied-configuration annotations" )
2017-02-16 08:21:19 +00:00
return cmd
}
func ( o * SetLastAppliedOptions ) Complete ( f cmdutil . Factory , cmd * cobra . Command ) error {
2018-04-26 13:30:21 +00:00
o . dryRun = cmdutil . GetDryRunFlag ( cmd )
o . output = cmdutil . GetFlagString ( cmd , "output" )
o . shortOutput = o . output == "name"
2017-02-16 08:21:19 +00:00
2018-04-18 15:20:33 +00:00
var err error
2018-04-26 13:30:21 +00:00
o . namespace , o . enforceNamespace , err = f . DefaultNamespace ( )
if err != nil {
return err
}
o . builder = f . NewBuilder ( )
o . unstructuredClientForMapping = f . UnstructuredClientForMapping
if o . dryRun {
// TODO(juanvallejo): This can be cleaned up even further by creating
// a PrintFlags struct that binds the --dry-run flag, and whose
// ToPrinter method returns a printer that understands how to print
// this success message.
o . PrintFlags . Complete ( "%s (dry run)" )
}
printer , err := o . PrintFlags . ToPrinter ( )
if err != nil {
return err
}
o . PrintObj = printer . PrintObj
return nil
2017-02-16 08:21:19 +00:00
}
2018-04-26 13:30:21 +00:00
func ( o * SetLastAppliedOptions ) Validate ( ) error {
r := o . builder .
2017-11-14 04:01:51 +00:00
Unstructured ( ) .
2018-04-26 13:30:21 +00:00
NamespaceParam ( o . namespace ) . DefaultNamespace ( ) .
FilenameParam ( o . enforceNamespace , & o . FilenameOptions ) .
2017-02-16 08:21:19 +00:00
Flatten ( ) .
Do ( )
2017-11-14 04:01:51 +00:00
err := r . Visit ( func ( info * resource . Info , err error ) error {
2017-02-16 08:21:19 +00:00
if err != nil {
return err
}
2018-05-03 12:05:50 +00:00
patchBuf , diffBuf , patchType , err := editor . GetApplyPatch ( info . Object . ( runtime . Unstructured ) )
2017-02-16 08:21:19 +00:00
if err != nil {
return err
}
// Verify the object exists in the cluster before trying to patch it.
if err := info . Get ( ) ; err != nil {
if errors . IsNotFound ( err ) {
return err
} else {
2018-01-29 07:14:04 +00:00
return cmdutil . AddSourceToErr ( fmt . Sprintf ( "retrieving current configuration of:\n%s\nfrom server for:" , info . String ( ) ) , info . Source , err )
2017-02-16 08:21:19 +00:00
}
}
2018-04-23 14:23:01 +00:00
originalBuf , err := kubectl . GetOriginalConfiguration ( info . Object )
2017-02-16 08:21:19 +00:00
if err != nil {
2018-01-29 07:14:04 +00:00
return cmdutil . AddSourceToErr ( fmt . Sprintf ( "retrieving current configuration of:\n%s\nfrom server for:" , info . String ( ) ) , info . Source , err )
2017-02-16 08:21:19 +00:00
}
2017-11-14 04:01:51 +00:00
if originalBuf == nil && ! o . CreateAnnotation {
2018-04-26 13:30:21 +00:00
return fmt . Errorf ( "no last-applied-configuration annotation found on resource: %s, to create the annotation, run the command with --create-annotation" , info . Name )
2017-02-16 08:21:19 +00:00
}
//only add to PatchBufferList when changed
2017-11-14 04:01:51 +00:00
if ! bytes . Equal ( cmdutil . StripComments ( originalBuf ) , cmdutil . StripComments ( diffBuf ) ) {
2017-02-26 12:36:20 +00:00
p := PatchBuffer { Patch : patchBuf , PatchType : patchType }
2018-04-26 13:30:21 +00:00
o . patchBufferList = append ( o . patchBufferList , p )
o . infoList = append ( o . infoList , info )
2017-02-16 08:21:19 +00:00
} else {
fmt . Fprintf ( o . Out , "set-last-applied %s: no changes required.\n" , info . Name )
}
return nil
} )
2017-05-25 20:37:56 +00:00
return err
2017-02-16 08:21:19 +00:00
}
2018-04-26 13:30:21 +00:00
func ( o * SetLastAppliedOptions ) RunSetLastApplied ( ) error {
for i , patch := range o . patchBufferList {
info := o . infoList [ i ]
2018-05-03 12:05:50 +00:00
finalObj := info . Object
2018-04-26 13:30:21 +00:00
if ! o . dryRun {
2017-02-16 08:21:19 +00:00
mapping := info . ResourceMapping ( )
2018-04-26 13:30:21 +00:00
client , err := o . unstructuredClientForMapping ( mapping )
2017-02-16 08:21:19 +00:00
if err != nil {
return err
}
helper := resource . NewHelper ( client , mapping )
2018-05-03 12:05:50 +00:00
finalObj , err = helper . Patch ( o . namespace , info . Name , patch . PatchType , patch . Patch )
2017-02-16 08:21:19 +00:00
if err != nil {
return err
}
}
2018-05-03 12:05:50 +00:00
if err := o . PrintObj ( finalObj , o . Out ) ; err != nil {
2017-02-16 08:21:19 +00:00
return err
}
}
return nil
}