2015-01-09 23:53:06 +00:00
/ *
2016-06-03 00:25:58 +00:00
Copyright 2014 The Kubernetes Authors .
2015-01-09 23:53:06 +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 .
* /
2018-10-05 11:06:12 +00:00
package scale
2015-01-09 23:53:06 +00:00
import (
"fmt"
2018-04-24 04:40:35 +00:00
"time"
2015-01-09 23:53:06 +00:00
2015-04-11 06:06:05 +00:00
"github.com/spf13/cobra"
2018-11-09 18:49:10 +00:00
"k8s.io/klog"
2015-04-11 06:06:05 +00:00
2018-04-24 04:40:35 +00:00
"k8s.io/apimachinery/pkg/api/meta"
2018-05-01 17:02:44 +00:00
"k8s.io/apimachinery/pkg/runtime/schema"
2018-04-19 14:41:17 +00:00
"k8s.io/apimachinery/pkg/types"
2018-08-21 10:46:39 +00:00
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/genericclioptions/printers"
"k8s.io/cli-runtime/pkg/genericclioptions/resource"
2018-08-02 18:24:22 +00:00
"k8s.io/client-go/kubernetes"
batchclient "k8s.io/client-go/kubernetes/typed/batch/v1"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/kubectl"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
2017-07-07 04:04:11 +00:00
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
2018-10-10 18:29:30 +00:00
"k8s.io/kubernetes/pkg/kubectl/util/templates"
2015-01-09 23:53:06 +00:00
)
2016-05-20 17:49:56 +00:00
var (
2017-02-16 03:47:00 +00:00
scaleLong = templates . LongDesc ( i18n . T ( `
2018-03-01 09:00:05 +00:00
Set a new size for a Deployment , ReplicaSet , Replication Controller , or StatefulSet .
2015-01-09 23:53:06 +00:00
2016-05-20 17:49:56 +00:00
Scale also allows users to specify one or more preconditions for the scale action .
2016-10-07 22:24:42 +00:00
2016-05-20 17:49:56 +00:00
If -- current - replicas or -- resource - version is specified , it is validated before the
scale is attempted , and it is guaranteed that the precondition holds true when the
2017-03-15 03:49:10 +00:00
scale is sent to the server . ` ) )
2016-10-07 22:24:42 +00:00
2017-02-16 03:47:00 +00:00
scaleExample = templates . Examples ( i18n . T ( `
2016-05-20 17:49:56 +00:00
# Scale a replicaset named ' foo ' to 3.
kubectl scale -- replicas = 3 rs / foo
2015-01-09 23:53:06 +00:00
2016-05-20 17:49:56 +00:00
# Scale a resource identified by type and name specified in "foo.yaml" to 3.
kubectl scale -- replicas = 3 - f foo . yaml
2015-08-11 09:05:28 +00:00
2016-05-20 17:49:56 +00:00
# If the deployment named mysql ' s current size is 2 , scale mysql to 3.
kubectl scale -- current - replicas = 2 -- replicas = 3 deployment / mysql
2015-06-29 09:37:11 +00:00
2016-05-20 17:49:56 +00:00
# Scale multiple replication controllers .
kubectl scale -- replicas = 5 rc / foo rc / bar rc / baz
2015-11-13 12:44:03 +00:00
2018-03-01 09:00:05 +00:00
# Scale statefulset named ' web ' to 3.
kubectl scale -- replicas = 3 statefulset / web ` ) )
2015-02-20 21:28:43 +00:00
)
2015-02-03 17:59:21 +00:00
2018-10-05 12:38:38 +00:00
const (
timeout = 5 * time . Minute
)
2018-04-19 14:41:17 +00:00
type ScaleOptions struct {
FilenameOptions resource . FilenameOptions
RecordFlags * genericclioptions . RecordFlags
2018-05-02 19:15:47 +00:00
PrintFlags * genericclioptions . PrintFlags
2018-04-24 04:40:35 +00:00
PrintObj printers . ResourcePrinterFunc
2018-04-26 13:30:21 +00:00
Selector string
All bool
Replicas int
2018-04-24 04:40:35 +00:00
ResourceVersion string
CurrentReplicas int
2018-04-26 13:30:21 +00:00
Timeout time . Duration
Recorder genericclioptions . Recorder
builder * resource . Builder
namespace string
enforceNamespace bool
args [ ] string
shortOutput bool
2018-08-02 18:24:22 +00:00
clientSet kubernetes . Interface
2018-04-26 13:30:21 +00:00
scaler kubectl . Scaler
unstructuredClientForMapping func ( mapping * meta . RESTMapping ) ( resource . RESTClient , error )
parent string
2018-04-24 04:40:35 +00:00
genericclioptions . IOStreams
2018-04-19 14:41:17 +00:00
}
2018-04-24 04:40:35 +00:00
func NewScaleOptions ( ioStreams genericclioptions . IOStreams ) * ScaleOptions {
2018-04-19 14:41:17 +00:00
return & ScaleOptions {
2018-07-02 14:05:24 +00:00
PrintFlags : genericclioptions . NewPrintFlags ( "scaled" ) ,
2018-04-26 13:30:21 +00:00
RecordFlags : genericclioptions . NewRecordFlags ( ) ,
2018-04-24 04:40:35 +00:00
CurrentReplicas : - 1 ,
2018-04-26 13:30:21 +00:00
Recorder : genericclioptions . NoopRecorder { } ,
IOStreams : ioStreams ,
2018-04-19 14:41:17 +00:00
}
}
2015-05-21 21:10:25 +00:00
// NewCmdScale returns a cobra command with the appropriate configuration and flags to run scale
2018-04-26 13:30:21 +00:00
func NewCmdScale ( f cmdutil . Factory , ioStreams genericclioptions . IOStreams ) * cobra . Command {
o := NewScaleOptions ( ioStreams )
2015-08-14 18:46:43 +00:00
2018-03-29 20:16:03 +00:00
validArgs := [ ] string { "deployment" , "replicaset" , "replicationcontroller" , "statefulset" }
2016-08-22 02:46:50 +00:00
2015-02-20 21:28:43 +00:00
cmd := & cobra . Command {
2018-10-05 19:59:38 +00:00
Use : "scale [--resource-version=version] [--current-replicas=count] --replicas=COUNT (-f FILENAME | TYPE NAME)" ,
2017-10-11 06:26:02 +00:00
DisableFlagsInUseLine : true ,
2018-10-05 19:59:38 +00:00
Short : i18n . T ( "Set a new size for a Deployment, ReplicaSet, Replication Controller, or Job" ) ,
Long : scaleLong ,
Example : scaleExample ,
2015-01-09 23:53:06 +00:00
Run : func ( cmd * cobra . Command , args [ ] string ) {
2018-04-24 04:40:35 +00:00
cmdutil . CheckErr ( o . Complete ( f , cmd , args ) )
2018-04-26 13:30:21 +00:00
cmdutil . CheckErr ( o . Validate ( cmd ) )
2018-04-24 04:40:35 +00:00
cmdutil . CheckErr ( o . RunScale ( ) )
2015-01-09 23:53:06 +00:00
} ,
2018-05-07 19:25:40 +00:00
ValidArgs : validArgs ,
2015-01-09 23:53:06 +00:00
}
2018-04-19 14:41:17 +00:00
o . RecordFlags . AddFlags ( cmd )
2018-04-24 04:40:35 +00:00
o . PrintFlags . AddFlags ( cmd )
2018-04-19 14:41:17 +00:00
2018-04-24 04:40:35 +00:00
cmd . Flags ( ) . StringVarP ( & o . Selector , "selector" , "l" , o . Selector , "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)" )
cmd . Flags ( ) . BoolVar ( & o . All , "all" , o . All , "Select all resources in the namespace of the specified resource types" )
cmd . Flags ( ) . StringVar ( & o . ResourceVersion , "resource-version" , o . ResourceVersion , i18n . T ( "Precondition for resource version. Requires that the current resource version match this value in order to scale." ) )
cmd . Flags ( ) . IntVar ( & o . CurrentReplicas , "current-replicas" , o . CurrentReplicas , "Precondition for current size. Requires that the current size of the resource match this value in order to scale." )
cmd . Flags ( ) . IntVar ( & o . Replicas , "replicas" , o . Replicas , "The new desired number of replicas. Required." )
2015-03-17 15:49:35 +00:00
cmd . MarkFlagRequired ( "replicas" )
2018-04-26 13:30:21 +00:00
cmd . Flags ( ) . DurationVar ( & o . Timeout , "timeout" , 0 , "The length of time to wait before giving up on a scale operation, zero means don't wait. Any other values should contain a corresponding time unit (e.g. 1s, 2m, 3h)." )
cmdutil . AddFilenameOptionFlags ( cmd , & o . FilenameOptions , "identifying the resource to set a new size" )
2015-01-09 23:53:06 +00:00
return cmd
}
2015-03-09 22:08:16 +00:00
2018-04-24 04:40:35 +00:00
func ( o * ScaleOptions ) Complete ( f cmdutil . Factory , cmd * cobra . Command , args [ ] string ) error {
2018-04-19 14:41:17 +00:00
var err error
2018-05-21 19:27:11 +00:00
o . RecordFlags . Complete ( cmd )
2018-04-26 13:30:21 +00:00
o . Recorder , err = o . RecordFlags . ToRecorder ( )
2018-04-24 04:40:35 +00:00
if err != nil {
return err
}
2018-04-26 13:30:21 +00:00
printer , err := o . PrintFlags . ToPrinter ( )
2018-04-19 14:41:17 +00:00
if err != nil {
return err
}
2018-04-26 13:30:21 +00:00
o . PrintObj = printer . PrintObj
2018-04-19 14:41:17 +00:00
2018-05-24 13:33:36 +00:00
o . namespace , o . enforceNamespace , err = f . ToRawKubeConfigLoader ( ) . Namespace ( )
2018-04-24 04:40:35 +00:00
if err != nil {
return err
}
2018-04-26 13:30:21 +00:00
o . builder = f . NewBuilder ( )
o . args = args
o . shortOutput = cmdutil . GetFlagString ( cmd , "output" ) == "name"
2018-08-02 18:24:22 +00:00
o . clientSet , err = f . KubernetesClientSet ( )
2015-03-09 22:08:16 +00:00
if err != nil {
return err
}
2018-05-10 13:00:33 +00:00
o . scaler , err = scaler ( f )
2018-04-24 04:40:35 +00:00
if err != nil {
return err
2018-02-21 15:18:44 +00:00
}
2018-04-26 13:30:21 +00:00
o . unstructuredClientForMapping = f . UnstructuredClientForMapping
o . parent = cmd . Parent ( ) . Name ( )
2018-02-21 15:18:44 +00:00
2018-04-24 04:40:35 +00:00
return nil
}
2018-04-26 13:30:21 +00:00
func ( o * ScaleOptions ) Validate ( cmd * cobra . Command ) error {
2018-04-24 04:40:35 +00:00
if o . Replicas < 0 {
return fmt . Errorf ( "The --replicas=COUNT flag is required, and COUNT must be greater than or equal to 0" )
}
2017-08-23 09:09:16 +00:00
2018-04-26 13:30:21 +00:00
return nil
}
// RunScale executes the scaling
func ( o * ScaleOptions ) RunScale ( ) error {
r := o . builder .
2018-01-15 11:31:45 +00:00
Unstructured ( ) .
2015-04-11 06:06:05 +00:00
ContinueOnError ( ) .
2018-04-26 13:30:21 +00:00
NamespaceParam ( o . namespace ) . DefaultNamespace ( ) .
FilenameParam ( o . enforceNamespace , & o . FilenameOptions ) .
ResourceTypeOrNameArgs ( o . All , o . args ... ) .
2015-04-11 06:06:05 +00:00
Flatten ( ) .
2018-04-24 04:40:35 +00:00
LabelSelectorParam ( o . Selector ) .
2015-04-11 06:06:05 +00:00
Do ( )
2018-04-24 04:40:35 +00:00
err := r . Err ( )
2015-04-11 06:06:05 +00:00
if err != nil {
return err
}
2016-04-14 22:00:40 +00:00
infos := [ ] * resource . Info { }
err = r . Visit ( func ( info * resource . Info , err error ) error {
if err == nil {
infos = append ( infos , info )
}
return nil
} )
2015-03-09 22:08:16 +00:00
2018-04-24 04:40:35 +00:00
if len ( o . ResourceVersion ) != 0 && len ( infos ) > 1 {
2015-11-13 12:44:03 +00:00
return fmt . Errorf ( "cannot use --resource-version with multiple resources" )
2015-06-29 09:37:11 +00:00
}
2018-04-26 13:30:21 +00:00
precondition := & kubectl . ScalePrecondition { Size : o . CurrentReplicas , ResourceVersion : o . ResourceVersion }
2018-05-17 15:27:44 +00:00
retry := kubectl . NewRetryParams ( 1 * time . Second , 5 * time . Minute )
2018-04-04 12:57:07 +00:00
var waitForReplicas * kubectl . RetryParams
2018-04-26 13:30:21 +00:00
if o . Timeout != 0 {
2018-05-17 15:27:44 +00:00
waitForReplicas = kubectl . NewRetryParams ( 1 * time . Second , timeout )
2018-04-04 12:57:07 +00:00
}
2016-04-14 22:00:40 +00:00
counter := 0
err = r . Visit ( func ( info * resource . Info , err error ) error {
if err != nil {
return err
}
2018-04-04 12:57:07 +00:00
mapping := info . ResourceMapping ( )
2018-05-01 17:02:44 +00:00
if mapping . Resource . GroupResource ( ) == ( schema . GroupResource { Group : "batch" , Resource : "jobs" } ) {
2018-04-04 12:57:07 +00:00
// go down the legacy jobs path. This can be removed in 3.14 For now, contain it.
2018-04-26 13:30:21 +00:00
fmt . Fprintf ( o . ErrOut , "%s scale job is DEPRECATED and will be removed in a future version.\n" , o . parent )
2016-04-14 22:00:40 +00:00
2018-04-26 13:30:21 +00:00
if err := ScaleJob ( info , o . clientSet . Batch ( ) , uint ( o . Replicas ) , precondition , retry , waitForReplicas ) ; err != nil {
2018-04-04 12:57:07 +00:00
return err
}
2016-04-14 22:00:40 +00:00
2018-04-04 12:57:07 +00:00
} else {
2018-05-01 17:02:44 +00:00
if err := o . scaler . Scale ( info . Namespace , info . Name , uint ( o . Replicas ) , precondition , retry , waitForReplicas , mapping . Resource . GroupResource ( ) ) ; err != nil {
2018-04-04 12:57:07 +00:00
return err
}
2015-06-29 09:37:11 +00:00
}
2018-04-04 12:57:07 +00:00
2018-04-19 14:41:17 +00:00
// if the recorder makes a change, compute and create another patch
if mergePatch , err := o . Recorder . MakeRecordMergePatch ( info . Object ) ; err != nil {
2018-11-09 18:49:10 +00:00
klog . V ( 4 ) . Infof ( "error recording current command: %v" , err )
2018-04-19 14:41:17 +00:00
} else if len ( mergePatch ) > 0 {
2018-04-26 13:30:21 +00:00
client , err := o . unstructuredClientForMapping ( mapping )
2016-01-22 18:33:23 +00:00
if err != nil {
return err
}
helper := resource . NewHelper ( client , mapping )
2018-08-30 13:33:34 +00:00
if _ , err := helper . Patch ( info . Namespace , info . Name , types . MergePatchType , mergePatch , nil ) ; err != nil {
2018-11-09 18:49:10 +00:00
klog . V ( 4 ) . Infof ( "error recording reason: %v" , err )
2016-01-22 18:33:23 +00:00
}
}
2018-04-19 14:41:17 +00:00
2016-04-14 22:00:40 +00:00
counter ++
2018-04-24 04:40:35 +00:00
return o . PrintObj ( info . Object , o . Out )
2016-04-14 22:00:40 +00:00
} )
if err != nil {
return err
2015-03-09 22:08:16 +00:00
}
2016-04-14 22:00:40 +00:00
if counter == 0 {
return fmt . Errorf ( "no objects passed to scale" )
}
return nil
2015-03-09 22:08:16 +00:00
}
2018-04-04 12:57:07 +00:00
func ScaleJob ( info * resource . Info , jobsClient batchclient . JobsGetter , count uint , preconditions * kubectl . ScalePrecondition , retry , waitForReplicas * kubectl . RetryParams ) error {
2018-10-05 11:06:12 +00:00
scaler := JobPsuedoScaler {
2018-04-04 12:57:07 +00:00
JobsClient : jobsClient ,
}
2018-10-05 11:06:12 +00:00
var jobPreconditions * ScalePrecondition
2018-04-04 12:57:07 +00:00
if preconditions != nil {
2018-10-05 11:06:12 +00:00
jobPreconditions = & ScalePrecondition { Size : preconditions . Size , ResourceVersion : preconditions . ResourceVersion }
2018-04-04 12:57:07 +00:00
}
2018-10-05 11:06:12 +00:00
var jobRetry * RetryParams
2018-04-04 12:57:07 +00:00
if retry != nil {
2018-10-05 11:06:12 +00:00
jobRetry = & RetryParams { Interval : retry . Interval , Timeout : retry . Timeout }
2018-04-04 12:57:07 +00:00
}
2018-10-05 11:06:12 +00:00
var jobWaitForReplicas * RetryParams
2018-04-04 12:57:07 +00:00
if waitForReplicas != nil {
2018-10-05 11:06:12 +00:00
jobWaitForReplicas = & RetryParams { Interval : waitForReplicas . Interval , Timeout : waitForReplicas . Timeout }
2018-04-04 12:57:07 +00:00
}
return scaler . Scale ( info . Namespace , info . Name , count , jobPreconditions , jobRetry , jobWaitForReplicas )
}
2018-05-10 13:00:33 +00:00
func scaler ( f cmdutil . Factory ) ( kubectl . Scaler , error ) {
2018-05-24 19:57:19 +00:00
scalesGetter , err := cmdutil . ScaleClientFn ( f )
2018-05-10 13:00:33 +00:00
if err != nil {
return nil , err
}
return kubectl . NewScaler ( scalesGetter ) , nil
}