2017-05-22 06:53:41 +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 set
import (
"errors"
"fmt"
"io"
"github.com/spf13/cobra"
2017-11-10 18:36:12 +00:00
"k8s.io/api/core/v1"
2017-05-22 06:53:41 +00:00
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/resource"
2017-07-07 04:04:11 +00:00
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
2017-05-22 06:53:41 +00:00
)
var (
serviceaccountResources = `
replicationcontroller ( rc ) , deployment ( deploy ) , daemonset ( ds ) , job , replicaset ( rs ) , statefulset `
serviceaccountLong = templates . LongDesc ( i18n . T ( `
Update ServiceAccount of pod template resources .
Possible resources ( case insensitive ) can be :
` + serviceaccountResources ) )
serviceaccountExample = templates . Examples ( i18n . T ( `
# Set Deployment nginx - deployment ' s ServiceAccount to serviceaccount1
kubectl set serviceaccount deployment nginx - deployment serviceaccount1
# Print the result ( in yaml format ) of updated nginx deployment with serviceaccount from local file , without hitting apiserver
kubectl set sa - f nginx - deployment . yaml serviceaccount1 -- local -- dry - run - o yaml
` ) )
)
// serviceAccountConfig encapsulates the data required to perform the operation.
type serviceAccountConfig struct {
fileNameOptions resource . FilenameOptions
out io . Writer
err io . Writer
dryRun bool
2017-11-10 18:36:12 +00:00
cmd * cobra . Command
2017-05-22 06:53:41 +00:00
shortOutput bool
all bool
record bool
output string
changeCause string
local bool
2017-11-10 18:36:12 +00:00
updatePodSpecForObject func ( runtime . Object , func ( * v1 . PodSpec ) error ) ( bool , error )
2017-05-22 06:53:41 +00:00
infos [ ] * resource . Info
serviceAccountName string
}
// NewCmdServiceAccount returns the "set serviceaccount" command.
func NewCmdServiceAccount ( f cmdutil . Factory , out , err io . Writer ) * cobra . Command {
saConfig := & serviceAccountConfig {
out : out ,
err : err ,
}
cmd := & cobra . Command {
2017-10-11 06:26:02 +00:00
Use : "serviceaccount (-f FILENAME | TYPE NAME) SERVICE_ACCOUNT" ,
DisableFlagsInUseLine : true ,
Aliases : [ ] string { "sa" } ,
Short : i18n . T ( "Update ServiceAccount of a resource" ) ,
Long : serviceaccountLong ,
Example : serviceaccountExample ,
2017-05-22 06:53:41 +00:00
Run : func ( cmd * cobra . Command , args [ ] string ) {
cmdutil . CheckErr ( saConfig . Complete ( f , cmd , args ) )
cmdutil . CheckErr ( saConfig . Run ( ) )
} ,
}
cmdutil . AddPrinterFlags ( cmd )
usage := "identifying the resource to get from a server."
cmdutil . AddFilenameOptionFlags ( cmd , & saConfig . fileNameOptions , usage )
2018-02-24 09:01:30 +00:00
cmd . Flags ( ) . BoolVar ( & saConfig . all , "all" , saConfig . all , "Select all resources, including uninitialized ones, in the namespace of the specified resource types" )
cmd . Flags ( ) . BoolVar ( & saConfig . local , "local" , saConfig . local , "If true, set serviceaccount will NOT contact api-server but run locally." )
2017-05-22 06:53:41 +00:00
cmdutil . AddRecordFlag ( cmd )
cmdutil . AddDryRunFlag ( cmd )
2017-08-11 06:21:44 +00:00
cmdutil . AddIncludeUninitializedFlag ( cmd )
2017-05-22 06:53:41 +00:00
return cmd
}
// Complete configures serviceAccountConfig from command line args.
func ( saConfig * serviceAccountConfig ) Complete ( f cmdutil . Factory , cmd * cobra . Command , args [ ] string ) error {
saConfig . shortOutput = cmdutil . GetFlagString ( cmd , "output" ) == "name"
saConfig . record = cmdutil . GetRecordFlag ( cmd )
saConfig . changeCause = f . Command ( cmd , false )
saConfig . dryRun = cmdutil . GetDryRunFlag ( cmd )
saConfig . output = cmdutil . GetFlagString ( cmd , "output" )
saConfig . updatePodSpecForObject = f . UpdatePodSpecForObject
2017-11-10 18:36:12 +00:00
saConfig . cmd = cmd
2017-05-22 06:53:41 +00:00
cmdNamespace , enforceNamespace , err := f . DefaultNamespace ( )
if err != nil {
return err
}
if len ( args ) == 0 {
return errors . New ( "serviceaccount is required" )
}
saConfig . serviceAccountName = args [ len ( args ) - 1 ]
resources := args [ : len ( args ) - 1 ]
2017-08-11 06:21:44 +00:00
includeUninitialized := cmdutil . ShouldIncludeUninitialized ( cmd , false )
2017-11-15 04:03:06 +00:00
builder := f . NewBuilder ( ) .
2017-11-15 06:10:30 +00:00
Internal ( ) .
2017-11-15 04:03:06 +00:00
LocalParam ( saConfig . local ) .
ContinueOnError ( ) .
2017-05-22 06:53:41 +00:00
NamespaceParam ( cmdNamespace ) . DefaultNamespace ( ) .
FilenameParam ( enforceNamespace , & saConfig . fileNameOptions ) .
2017-08-11 06:21:44 +00:00
IncludeUninitialized ( includeUninitialized ) .
2017-05-22 06:53:41 +00:00
Flatten ( )
if ! saConfig . local {
builder . ResourceTypeOrNameArgs ( saConfig . all , resources ... ) .
Latest ( )
}
saConfig . infos , err = builder . Do ( ) . Infos ( )
if err != nil {
return err
}
return nil
}
// Run creates and applies the patch either locally or calling apiserver.
func ( saConfig * serviceAccountConfig ) Run ( ) error {
patchErrs := [ ] error { }
patchFn := func ( info * resource . Info ) ( [ ] byte , error ) {
2017-11-14 04:01:51 +00:00
info . Object = info . AsVersioned ( )
saConfig . updatePodSpecForObject ( info . Object , func ( podSpec * v1 . PodSpec ) error {
2017-05-22 06:53:41 +00:00
podSpec . ServiceAccountName = saConfig . serviceAccountName
return nil
} )
2018-02-21 17:10:38 +00:00
return runtime . Encode ( cmdutil . InternalVersionJSONEncoder ( ) , info . Object )
2017-05-22 06:53:41 +00:00
}
2018-02-21 17:10:38 +00:00
patches := CalculatePatches ( saConfig . infos , cmdutil . InternalVersionJSONEncoder ( ) , patchFn )
2017-05-22 06:53:41 +00:00
for _ , patch := range patches {
info := patch . Info
if patch . Err != nil {
patchErrs = append ( patchErrs , fmt . Errorf ( "error: %s/%s %v\n" , info . Mapping . Resource , info . Name , patch . Err ) )
continue
}
if saConfig . local || saConfig . dryRun {
2018-02-21 01:14:21 +00:00
if err := cmdutil . PrintObject ( saConfig . cmd , patch . Info . AsVersioned ( ) , saConfig . out ) ; err != nil {
2017-11-10 18:36:12 +00:00
return err
}
2017-05-22 06:53:41 +00:00
continue
}
patched , err := resource . NewHelper ( info . Client , info . Mapping ) . Patch ( info . Namespace , info . Name , types . StrategicMergePatchType , patch . Patch )
if err != nil {
patchErrs = append ( patchErrs , fmt . Errorf ( "failed to patch ServiceAccountName %v" , err ) )
continue
}
info . Refresh ( patched , true )
if saConfig . record || cmdutil . ContainsChangeCause ( info ) {
if patch , patchType , err := cmdutil . ChangeResourcePatch ( info , saConfig . changeCause ) ; err == nil {
if patched , err = resource . NewHelper ( info . Client , info . Mapping ) . Patch ( info . Namespace , info . Name , patchType , patch ) ; err != nil {
fmt . Fprintf ( saConfig . err , "WARNING: changes to %s/%s can't be recorded: %v\n" , info . Mapping . Resource , info . Name , err )
}
}
}
if len ( saConfig . output ) > 0 {
2018-02-21 01:14:21 +00:00
if err := cmdutil . PrintObject ( saConfig . cmd , info . AsVersioned ( ) , saConfig . out ) ; err != nil {
2017-11-10 18:36:12 +00:00
return err
}
continue
2017-05-22 06:53:41 +00:00
}
2018-02-21 01:14:21 +00:00
cmdutil . PrintSuccess ( saConfig . shortOutput , saConfig . out , info . Object , saConfig . dryRun , "serviceaccount updated" )
2017-05-22 06:53:41 +00:00
}
return utilerrors . NewAggregate ( patchErrs )
}