2016-06-10 21:25:56 +00:00
/ *
Copyright 2016 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 (
"fmt"
"io"
2016-10-24 13:17:55 +00:00
"strings"
2016-06-10 21:25:56 +00:00
2018-04-04 20:23:33 +00:00
"k8s.io/kubernetes/pkg/printers"
2016-06-10 21:25:56 +00:00
"github.com/spf13/cobra"
2017-11-10 18:36:12 +00:00
"k8s.io/api/core/v1"
2016-06-10 21:25:56 +00:00
2017-01-11 14:09:48 +00:00
"k8s.io/apimachinery/pkg/runtime"
2017-01-16 20:13:59 +00:00
"k8s.io/apimachinery/pkg/types"
2017-01-11 14:09:48 +00:00
utilerrors "k8s.io/apimachinery/pkg/util/errors"
2016-06-10 21:25:56 +00:00
"k8s.io/kubernetes/pkg/kubectl"
2016-10-07 22:24:42 +00:00
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
2016-06-10 21:25:56 +00:00
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"
2016-06-10 21:25:56 +00:00
)
2016-10-07 22:24:42 +00:00
var (
resources_long = templates . LongDesc ( `
Specify compute resource requirements ( cpu , memory ) for any resource that defines a pod template . If a pod is successfully scheduled , it is guaranteed the amount of resource requested , but may burst up to its specified limits .
for each compute resource , if a limit is specified and a request is omitted , the request will default to the limit .
2016-12-05 02:58:56 +00:00
2016-10-24 13:17:55 +00:00
Possible resources include ( case insensitive ) : % s . ` )
2016-10-07 22:24:42 +00:00
resources_example = templates . Examples ( `
# Set a deployments nginx container cpu limits to "200m" and memory to "512Mi"
kubectl set resources deployment nginx - c = nginx -- limits = cpu = 200 m , memory = 512 Mi
# Set the resource request and limits for all containers in nginx
kubectl set resources deployment nginx -- limits = cpu = 200 m , memory = 512 Mi -- requests = cpu = 100 m , memory = 256 Mi
# Remove the resource requests for resources on containers in nginx
kubectl set resources deployment nginx -- limits = cpu = 0 , memory = 0 -- requests = cpu = 0 , memory = 0
# Print the result ( in yaml format ) of updating nginx container limits from a local , without hitting the server
2016-10-26 13:48:46 +00:00
kubectl set resources - f path / to / file . yaml -- limits = cpu = 200 m , memory = 512 Mi -- local - o yaml ` )
2016-10-07 22:24:42 +00:00
)
2016-06-10 21:25:56 +00:00
// ResourcesOptions is the start of the data required to perform the operation. As new fields are added, add them here instead of
// referencing the cmd.Flags
type ResourcesOptions struct {
resource . FilenameOptions
2018-04-04 20:23:33 +00:00
PrintFlags * printers . PrintFlags
2016-06-10 21:25:56 +00:00
Infos [ ] * resource . Info
Out io . Writer
Err io . Writer
Selector string
ContainerSelector string
2017-05-23 07:49:07 +00:00
Output string
2016-06-10 21:25:56 +00:00
All bool
Record bool
ChangeCause string
2016-10-26 13:48:46 +00:00
Local bool
2016-06-10 21:25:56 +00:00
Cmd * cobra . Command
2018-04-04 20:23:33 +00:00
DryRun bool
PrintObj func ( runtime . Object ) error
2016-06-10 21:25:56 +00:00
Limits string
Requests string
2017-11-10 18:36:12 +00:00
ResourceRequirements v1 . ResourceRequirements
2016-06-10 21:25:56 +00:00
2017-11-10 18:36:12 +00:00
UpdatePodSpecForObject func ( obj runtime . Object , fn func ( * v1 . PodSpec ) error ) ( bool , error )
2016-06-10 21:25:56 +00:00
Resources [ ] string
}
2018-02-24 09:01:30 +00:00
// NewResourcesOptions returns a ResourcesOptions indicating all containers in the selected
// pod templates are selected by default.
func NewResourcesOptions ( out io . Writer , errOut io . Writer ) * ResourcesOptions {
return & ResourcesOptions {
2018-04-04 20:23:33 +00:00
PrintFlags : printers . NewPrintFlags ( "resource requirements updated" ) ,
2018-02-24 09:01:30 +00:00
Out : out ,
Err : errOut ,
ContainerSelector : "*" ,
2016-06-10 21:25:56 +00:00
}
2018-02-24 09:01:30 +00:00
}
func NewCmdResources ( f cmdutil . Factory , out io . Writer , errOut io . Writer ) * cobra . Command {
options := NewResourcesOptions ( out , errOut )
2016-06-10 21:25:56 +00:00
2016-10-24 13:17:55 +00:00
resourceTypesWithPodTemplate := [ ] string { }
for _ , resource := range f . SuggestedPodTemplateResources ( ) {
resourceTypesWithPodTemplate = append ( resourceTypesWithPodTemplate , resource . Resource )
2016-06-10 21:25:56 +00:00
}
cmd := & cobra . Command {
2017-10-11 06:26:02 +00:00
Use : "resources (-f FILENAME | TYPE NAME) ([--limits=LIMITS & --requests=REQUESTS]" ,
DisableFlagsInUseLine : true ,
2017-01-26 06:21:28 +00:00
Short : i18n . T ( "Update resource requests/limits on objects with pod templates" ) ,
2016-10-24 13:17:55 +00:00
Long : fmt . Sprintf ( resources_long , strings . Join ( resourceTypesWithPodTemplate , ", " ) ) ,
2016-06-10 21:25:56 +00:00
Example : resources_example ,
Run : func ( cmd * cobra . Command , args [ ] string ) {
cmdutil . CheckErr ( options . Complete ( f , cmd , args ) )
cmdutil . CheckErr ( options . Validate ( ) )
cmdutil . CheckErr ( options . Run ( ) )
} ,
}
2018-04-04 20:23:33 +00:00
options . PrintFlags . AddFlags ( cmd )
2016-06-10 21:25:56 +00:00
//usage := "Filename, directory, or URL to a file identifying the resource to get from the server"
//kubectl.AddJsonFilenameFlag(cmd, &options.Filenames, usage)
usage := "identifying the resource to get from a server."
cmdutil . AddFilenameOptionFlags ( cmd , & options . FilenameOptions , usage )
2017-08-25 08:28:21 +00:00
cmd . Flags ( ) . BoolVar ( & options . All , "all" , options . All , "Select all resources, including uninitialized ones, in the namespace of the specified resource types" )
2018-02-24 09:01:30 +00:00
cmd . Flags ( ) . StringVarP ( & options . Selector , "selector" , "l" , options . Selector , "Selector (label query) to filter on, not including uninitialized ones,supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)" )
cmd . Flags ( ) . StringVarP ( & options . ContainerSelector , "containers" , "c" , options . ContainerSelector , "The names of containers in the selected pod templates to change, all containers are selected by default - may use wildcards" )
2017-08-25 08:28:21 +00:00
cmd . Flags ( ) . BoolVar ( & options . Local , "local" , options . Local , "If true, set resources will NOT contact api-server but run locally." )
2016-06-10 21:25:56 +00:00
cmdutil . AddDryRunFlag ( cmd )
cmdutil . AddRecordFlag ( cmd )
2017-08-11 06:21:44 +00:00
cmdutil . AddIncludeUninitializedFlag ( cmd )
2016-06-10 21:25:56 +00:00
cmd . Flags ( ) . StringVar ( & options . Limits , "limits" , options . Limits , "The resource requirement requests for this container. For example, 'cpu=100m,memory=256Mi'. Note that server side components may assign requests depending on the server configuration, such as limit ranges." )
cmd . Flags ( ) . StringVar ( & options . Requests , "requests" , options . Requests , "The resource requirement requests for this container. For example, 'cpu=100m,memory=256Mi'. Note that server side components may assign requests depending on the server configuration, such as limit ranges." )
return cmd
}
func ( o * ResourcesOptions ) Complete ( f cmdutil . Factory , cmd * cobra . Command , args [ ] string ) error {
o . UpdatePodSpecForObject = f . UpdatePodSpecForObject
2017-05-23 07:49:07 +00:00
o . Output = cmdutil . GetFlagString ( cmd , "output" )
2016-06-10 21:25:56 +00:00
o . Record = cmdutil . GetRecordFlag ( cmd )
2017-02-25 15:40:50 +00:00
o . ChangeCause = f . Command ( cmd , false )
2016-06-10 21:25:56 +00:00
o . Cmd = cmd
2018-04-04 20:23:33 +00:00
o . DryRun = cmdutil . GetDryRunFlag ( o . Cmd )
o . PrintFlags . Complete ( o . DryRun )
printer , err := o . PrintFlags . ToPrinter ( )
if err != nil {
return err
}
o . PrintObj = func ( obj runtime . Object ) error {
return printer . PrintObj ( obj , o . Out )
}
2016-06-10 21:25:56 +00:00
cmdNamespace , enforceNamespace , err := f . DefaultNamespace ( )
if err != nil {
return err
}
2017-08-11 06:21:44 +00:00
includeUninitialized := cmdutil . ShouldIncludeUninitialized ( cmd , false )
2017-08-02 20:23:07 +00:00
builder := f . NewBuilder ( ) .
2017-11-15 06:10:30 +00:00
Internal ( ) .
2017-11-15 04:03:06 +00:00
LocalParam ( o . Local ) .
2016-06-10 21:25:56 +00:00
ContinueOnError ( ) .
NamespaceParam ( cmdNamespace ) . DefaultNamespace ( ) .
FilenameParam ( enforceNamespace , & o . FilenameOptions ) .
2017-08-11 06:21:44 +00:00
IncludeUninitialized ( includeUninitialized ) .
2016-06-10 21:25:56 +00:00
Flatten ( )
2017-05-16 21:52:51 +00:00
2017-11-14 03:43:58 +00:00
if ! o . Local {
2017-11-15 04:03:06 +00:00
builder . LabelSelectorParam ( o . Selector ) .
2017-11-14 03:43:58 +00:00
ResourceTypeOrNameArgs ( o . All , args ... ) .
Latest ( )
} else {
2017-07-11 14:19:27 +00:00
// if a --local flag was provided, and a resource was specified in the form
// <resource>/<name>, fail immediately as --local cannot query the api server
// for the specified resource.
2017-11-15 04:03:06 +00:00
// TODO: this should be in the builder - if someone specifies tuples, fail when
// local is true
2017-07-11 14:19:27 +00:00
if len ( args ) > 0 {
return resource . LocalResourceError
}
2016-06-10 21:25:56 +00:00
}
o . Infos , err = builder . Do ( ) . Infos ( )
if err != nil {
return err
}
return nil
}
func ( o * ResourcesOptions ) Validate ( ) error {
var err error
2017-08-25 08:28:21 +00:00
if o . All && len ( o . Selector ) > 0 {
return fmt . Errorf ( "cannot set --all and --selector at the same time" )
}
2016-06-10 21:25:56 +00:00
if len ( o . Limits ) == 0 && len ( o . Requests ) == 0 {
2016-10-18 15:42:58 +00:00
return fmt . Errorf ( "you must specify an update to requests or limits (in the form of --requests/--limits)" )
2016-06-10 21:25:56 +00:00
}
2017-11-10 18:36:12 +00:00
o . ResourceRequirements , err = kubectl . HandleResourceRequirementsV1 ( map [ string ] string { "limits" : o . Limits , "requests" : o . Requests } )
2016-06-10 21:25:56 +00:00
if err != nil {
return err
}
return nil
}
func ( o * ResourcesOptions ) Run ( ) error {
allErrs := [ ] error { }
2018-02-21 17:10:38 +00:00
patches := CalculatePatches ( o . Infos , cmdutil . InternalVersionJSONEncoder ( ) , func ( info * resource . Info ) ( [ ] byte , error ) {
2016-06-10 21:25:56 +00:00
transformed := false
2017-11-14 04:01:51 +00:00
info . Object = info . AsVersioned ( )
_ , err := o . UpdatePodSpecForObject ( info . Object , func ( spec * v1 . PodSpec ) error {
2016-06-10 21:25:56 +00:00
containers , _ := selectContainers ( spec . Containers , o . ContainerSelector )
if len ( containers ) != 0 {
for i := range containers {
2016-10-18 15:42:58 +00:00
if len ( o . Limits ) != 0 && len ( containers [ i ] . Resources . Limits ) == 0 {
2017-11-10 18:36:12 +00:00
containers [ i ] . Resources . Limits = make ( v1 . ResourceList )
2016-10-18 15:42:58 +00:00
}
for key , value := range o . ResourceRequirements . Limits {
containers [ i ] . Resources . Limits [ key ] = value
}
if len ( o . Requests ) != 0 && len ( containers [ i ] . Resources . Requests ) == 0 {
2017-11-10 18:36:12 +00:00
containers [ i ] . Resources . Requests = make ( v1 . ResourceList )
2016-10-18 15:42:58 +00:00
}
for key , value := range o . ResourceRequirements . Requests {
containers [ i ] . Resources . Requests [ key ] = value
}
2016-06-10 21:25:56 +00:00
transformed = true
}
} else {
allErrs = append ( allErrs , fmt . Errorf ( "error: unable to find container named %s" , o . ContainerSelector ) )
}
return nil
} )
2016-11-14 11:53:27 +00:00
if transformed && err == nil {
2018-02-21 17:10:38 +00:00
return runtime . Encode ( cmdutil . InternalVersionJSONEncoder ( ) , info . Object )
2016-11-14 11:53:27 +00:00
}
return nil , err
2016-06-10 21:25:56 +00:00
} )
for _ , patch := range patches {
info := patch . Info
if patch . Err != nil {
allErrs = append ( allErrs , fmt . Errorf ( "error: %s/%s %v\n" , info . Mapping . Resource , info . Name , patch . Err ) )
continue
}
//no changes
if string ( patch . Patch ) == "{}" || len ( patch . Patch ) == 0 {
allErrs = append ( allErrs , fmt . Errorf ( "info: %s %q was not changed\n" , info . Mapping . Resource , info . Name ) )
continue
}
2018-04-04 20:23:33 +00:00
if o . Local || o . DryRun {
if err := o . PrintObj ( patch . Info . AsVersioned ( ) ) ; err != nil {
2017-10-26 07:33:22 +00:00
return err
}
continue
2016-06-10 21:25:56 +00:00
}
2017-01-16 20:13:59 +00:00
obj , err := resource . NewHelper ( info . Client , info . Mapping ) . Patch ( info . Namespace , info . Name , types . StrategicMergePatchType , patch . Patch )
2016-06-10 21:25:56 +00:00
if err != nil {
allErrs = append ( allErrs , fmt . Errorf ( "failed to patch limit update to pod template %v\n" , err ) )
continue
}
info . Refresh ( obj , true )
//record this change (for rollout history)
if o . Record || cmdutil . ContainsChangeCause ( info ) {
if err := cmdutil . RecordChangeCause ( obj , o . ChangeCause ) ; err == nil {
if obj , err = resource . NewHelper ( info . Client , info . Mapping ) . Replace ( info . Namespace , info . Name , false , obj ) ; err != nil {
allErrs = append ( allErrs , fmt . Errorf ( "changes to %s/%s can't be recorded: %v\n" , info . Mapping . Resource , info . Name , err ) )
}
}
}
info . Refresh ( obj , true )
2017-05-23 07:49:07 +00:00
2018-04-04 20:23:33 +00:00
if err := o . PrintObj ( info . AsVersioned ( ) ) ; err != nil {
return err
2017-05-23 07:49:07 +00:00
}
2016-06-10 21:25:56 +00:00
}
return utilerrors . NewAggregate ( allErrs )
}