Commit 99fc3588 authored by Michail Kargakis's avatar Michail Kargakis

kubectl: Support scaling deployments

This commit adds support for using kubectl scale to scale deployments. Makes use of the deployments/scale endpoint instead of updating deployment.spec.replicas directly.
parent a7425bf0
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
.SH NAME .SH NAME
.PP .PP
kubectl scale \- Set a new size for a Replication Controller. kubectl scale \- Set a new size for a Replication Controller, Job, or Deployment.
.SH SYNOPSIS .SH SYNOPSIS
...@@ -13,7 +13,7 @@ kubectl scale \- Set a new size for a Replication Controller. ...@@ -13,7 +13,7 @@ kubectl scale \- Set a new size for a Replication Controller.
.SH DESCRIPTION .SH DESCRIPTION
.PP .PP
Set a new size for a Replication Controller. Set a new size for a Replication Controller, Job, or Deployment.
.PP .PP
Scale also allows users to specify one or more preconditions for the scale action. Scale also allows users to specify one or more preconditions for the scale action.
...@@ -25,11 +25,11 @@ scale is sent to the server. ...@@ -25,11 +25,11 @@ scale is sent to the server.
.SH OPTIONS .SH OPTIONS
.PP .PP
\fB\-\-current\-replicas\fP=\-1 \fB\-\-current\-replicas\fP=\-1
Precondition for current size. Requires that the current size of the replication controller match this value in order to scale. Precondition for current size. Requires that the current size of the resource match this value in order to scale.
.PP .PP
\fB\-f\fP, \fB\-\-filename\fP=[] \fB\-f\fP, \fB\-\-filename\fP=[]
Filename, directory, or URL to a file identifying the replication controller to set a new size Filename, directory, or URL to a file identifying the resource to set a new size
.PP .PP
\fB\-o\fP, \fB\-\-output\fP="" \fB\-o\fP, \fB\-\-output\fP=""
...@@ -148,16 +148,19 @@ scale is sent to the server. ...@@ -148,16 +148,19 @@ scale is sent to the server.
.nf .nf
# Scale replication controller named 'foo' to 3. # Scale replication controller named 'foo' to 3.
$ kubectl scale \-\-replicas=3 replicationcontrollers foo $ kubectl scale \-\-replicas=3 rc/foo
# Scale a replication controller identified by type and name specified in "foo\-controller.yaml" to 3. # Scale a resource identified by type and name specified in "foo.yaml" to 3.
$ kubectl scale \-\-replicas=3 \-f foo\-controller.yaml $ kubectl scale \-\-replicas=3 \-f foo.yaml
# If the replication controller named foo's current size is 2, scale foo to 3. # If the deployment named mysql's current size is 2, scale mysql to 3.
$ kubectl scale \-\-current\-replicas=2 \-\-replicas=3 replicationcontrollers foo $ kubectl scale \-\-current\-replicas=2 \-\-replicas=3 deployment/mysql
# Scale multiple replication controllers. # Scale multiple replication controllers.
$ kubectl scale \-\-replicas=5 rc/foo rc/bar $ kubectl scale \-\-replicas=5 rc/foo rc/bar rc/baz
# Scale job named 'cron' to 3.
$ kubectl scale \-\-replicas=3 job/cron
.fi .fi
.RE .RE
......
...@@ -101,10 +101,10 @@ kubectl ...@@ -101,10 +101,10 @@ kubectl
* [kubectl replace](kubectl_replace.md) - Replace a resource by filename or stdin. * [kubectl replace](kubectl_replace.md) - Replace a resource by filename or stdin.
* [kubectl rolling-update](kubectl_rolling-update.md) - Perform a rolling update of the given ReplicationController. * [kubectl rolling-update](kubectl_rolling-update.md) - Perform a rolling update of the given ReplicationController.
* [kubectl run](kubectl_run.md) - Run a particular image on the cluster. * [kubectl run](kubectl_run.md) - Run a particular image on the cluster.
* [kubectl scale](kubectl_scale.md) - Set a new size for a Replication Controller. * [kubectl scale](kubectl_scale.md) - Set a new size for a Replication Controller, Job, or Deployment.
* [kubectl version](kubectl_version.md) - Print the client and server version information. * [kubectl version](kubectl_version.md) - Print the client and server version information.
###### Auto generated by spf13/cobra on 24-Nov-2015 ###### Auto generated by spf13/cobra on 25-Nov-2015
<!-- BEGIN MUNGE: GENERATED_ANALYTICS --> <!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl.md?pixel)]() [![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl.md?pixel)]()
......
...@@ -33,12 +33,12 @@ Documentation for other releases can be found at ...@@ -33,12 +33,12 @@ Documentation for other releases can be found at
## kubectl scale ## kubectl scale
Set a new size for a Replication Controller. Set a new size for a Replication Controller, Job, or Deployment.
### Synopsis ### Synopsis
Set a new size for a Replication Controller. Set a new size for a Replication Controller, Job, or Deployment.
Scale also allows users to specify one or more preconditions for the scale action. Scale also allows users to specify one or more preconditions for the scale action.
If --current-replicas or --resource-version is specified, it is validated before the If --current-replicas or --resource-version is specified, it is validated before the
...@@ -53,23 +53,26 @@ kubectl scale [--resource-version=version] [--current-replicas=count] --replicas ...@@ -53,23 +53,26 @@ kubectl scale [--resource-version=version] [--current-replicas=count] --replicas
``` ```
# Scale replication controller named 'foo' to 3. # Scale replication controller named 'foo' to 3.
$ kubectl scale --replicas=3 replicationcontrollers foo $ kubectl scale --replicas=3 rc/foo
# Scale a replication controller identified by type and name specified in "foo-controller.yaml" to 3. # Scale a resource identified by type and name specified in "foo.yaml" to 3.
$ kubectl scale --replicas=3 -f foo-controller.yaml $ kubectl scale --replicas=3 -f foo.yaml
# If the replication controller named foo's current size is 2, scale foo to 3. # If the deployment named mysql's current size is 2, scale mysql to 3.
$ kubectl scale --current-replicas=2 --replicas=3 replicationcontrollers foo $ kubectl scale --current-replicas=2 --replicas=3 deployment/mysql
# Scale multiple replication controllers. # Scale multiple replication controllers.
$ kubectl scale --replicas=5 rc/foo rc/bar $ kubectl scale --replicas=5 rc/foo rc/bar rc/baz
# Scale job named 'cron' to 3.
$ kubectl scale --replicas=3 job/cron
``` ```
### Options ### Options
``` ```
--current-replicas=-1: Precondition for current size. Requires that the current size of the replication controller match this value in order to scale. --current-replicas=-1: Precondition for current size. Requires that the current size of the resource match this value in order to scale.
-f, --filename=[]: Filename, directory, or URL to a file identifying the replication controller to set a new size -f, --filename=[]: Filename, directory, or URL to a file identifying the resource to set a new size
-o, --output="": Output mode. Use "-o name" for shorter output (resource/name). -o, --output="": Output mode. Use "-o name" for shorter output (resource/name).
--replicas=-1: The new desired number of replicas. Required. --replicas=-1: The new desired number of replicas. Required.
--resource-version="": Precondition for resource version. Requires that the current resource version match this value in order to scale. --resource-version="": Precondition for resource version. Requires that the current resource version match this value in order to scale.
......
...@@ -219,6 +219,8 @@ runTests() { ...@@ -219,6 +219,8 @@ runTests() {
hpa_min_field=".spec.minReplicas" hpa_min_field=".spec.minReplicas"
hpa_max_field=".spec.maxReplicas" hpa_max_field=".spec.maxReplicas"
hpa_cpu_field=".spec.cpuUtilization.targetPercentage" hpa_cpu_field=".spec.cpuUtilization.targetPercentage"
job_parallelism_field=".spec.parallelism"
deployment_replicas=".spec.replicas"
# Passing no arguments to create is an error # Passing no arguments to create is an error
! kubectl create ! kubectl create
...@@ -873,6 +875,23 @@ __EOF__ ...@@ -873,6 +875,23 @@ __EOF__
# Clean-up # Clean-up
kubectl delete rc redis-{master,slave} "${kube_flags[@]}" kubectl delete rc redis-{master,slave} "${kube_flags[@]}"
### Scale a job
kubectl create -f docs/user-guide/job.yaml "${kube_flags[@]}"
# Command
kubectl scale --replicas=2 job/pi
# Post-condition: 2 replicas for pi
kube::test::get_object_assert 'job pi' "{{$job_parallelism_field}}" '2'
# Clean-up
kubectl delete job/pi "${kube_flags[@]}"
### Scale a deployment
kubectl create -f examples/extensions/deployment.yaml "${kube_flags[@]}"
# Command
kubectl scale --current-replicas=3 --replicas=1 deployment/nginx-deployment
# Post-condition: 1 replica for nginx-deployment
kube::test::get_object_assert 'deployment nginx-deployment' "{{$deployment_replicas}}" '1'
# Clean-up
kubectl delete deployment/nginx-deployment "${kube_flags[@]}"
### Expose replication controller as service ### Expose replication controller as service
# Pre-condition: 2 replicas # Pre-condition: 2 replicas
kube::test::get_object_assert 'rc frontend' "{{$rc_replicas_field}}" '2' kube::test::get_object_assert 'rc frontend' "{{$rc_replicas_field}}" '2'
......
...@@ -18,9 +18,9 @@ package extensions ...@@ -18,9 +18,9 @@ package extensions
import ( import (
"fmt" "fmt"
"sort" "sort"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/util/sets" "k8s.io/kubernetes/pkg/util/sets"
) )
...@@ -65,3 +65,21 @@ func PodSelectorAsSelector(ps *PodSelector) (labels.Selector, error) { ...@@ -65,3 +65,21 @@ func PodSelectorAsSelector(ps *PodSelector) (labels.Selector, error) {
sort.Sort(labels.ByKey(selector)) sort.Sort(labels.ByKey(selector))
return selector, nil return selector, nil
} }
// ScaleFromDeployment returns a scale subresource for a deployment.
func ScaleFromDeployment(deployment *Deployment) *Scale {
return &Scale{
ObjectMeta: api.ObjectMeta{
Name: deployment.Name,
Namespace: deployment.Namespace,
CreationTimestamp: deployment.CreationTimestamp,
},
Spec: ScaleSpec{
Replicas: deployment.Spec.Replicas,
},
Status: ScaleStatus{
Replicas: deployment.Status.Replicas,
Selector: deployment.Spec.Selector,
},
}
}
...@@ -45,10 +45,10 @@ func ControllerHasDesiredReplicas(c Interface, controller *api.ReplicationContro ...@@ -45,10 +45,10 @@ func ControllerHasDesiredReplicas(c Interface, controller *api.ReplicationContro
// JobHasDesiredParallelism returns a condition that will be true if the desired parallelism count // JobHasDesiredParallelism returns a condition that will be true if the desired parallelism count
// for a job equals the current active counts or is less by an appropriate successful/unsuccessful count. // for a job equals the current active counts or is less by an appropriate successful/unsuccessful count.
func JobHasDesiredParallelism(c Interface, job *extensions.Job) wait.ConditionFunc { func JobHasDesiredParallelism(c ExtensionsInterface, job *extensions.Job) wait.ConditionFunc {
return func() (bool, error) { return func() (bool, error) {
job, err := c.Extensions().Jobs(job.Namespace).Get(job.Name) job, err := c.Jobs(job.Namespace).Get(job.Name)
if err != nil { if err != nil {
return false, err return false, err
} }
...@@ -62,3 +62,17 @@ func JobHasDesiredParallelism(c Interface, job *extensions.Job) wait.ConditionFu ...@@ -62,3 +62,17 @@ func JobHasDesiredParallelism(c Interface, job *extensions.Job) wait.ConditionFu
return progress == 0, nil return progress == 0, nil
} }
} }
// DeploymentHasDesiredReplicas returns a condition that will be true if and only if
// the desired replica count for a deployment equals its updated replicas count.
// (non-terminated pods that have the desired template spec).
func DeploymentHasDesiredReplicas(c ExtensionsInterface, deployment *extensions.Deployment) wait.ConditionFunc {
return func() (bool, error) {
deployment, err := c.Deployments(deployment.Namespace).Get(deployment.Name)
if err != nil {
return false, err
}
return deployment.Status.UpdatedReplicas == deployment.Spec.Replicas, nil
}
}
...@@ -315,6 +315,11 @@ func (c *Fake) SwaggerSchema(version string) (*swagger.ApiDeclaration, error) { ...@@ -315,6 +315,11 @@ func (c *Fake) SwaggerSchema(version string) (*swagger.ApiDeclaration, error) {
return &swagger.ApiDeclaration{}, nil return &swagger.ApiDeclaration{}, nil
} }
// NewSimpleFakeExp returns a client that will respond with the provided objects
func NewSimpleFakeExp(objects ...runtime.Object) *FakeExperimental {
return &FakeExperimental{Fake: NewSimpleFake(objects...)}
}
type FakeExperimental struct { type FakeExperimental struct {
*Fake *Fake
} }
......
...@@ -36,23 +36,26 @@ type ScaleOptions struct { ...@@ -36,23 +36,26 @@ type ScaleOptions struct {
} }
const ( const (
scale_long = `Set a new size for a Replication Controller. scale_long = `Set a new size for a Replication Controller, Job, or Deployment.
Scale also allows users to specify one or more preconditions for the scale action. Scale also allows users to specify one or more preconditions for the scale action.
If --current-replicas or --resource-version is specified, it is validated before the 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 scale is attempted, and it is guaranteed that the precondition holds true when the
scale is sent to the server.` scale is sent to the server.`
scale_example = `# Scale replication controller named 'foo' to 3. scale_example = `# Scale replication controller named 'foo' to 3.
$ kubectl scale --replicas=3 replicationcontrollers foo $ kubectl scale --replicas=3 rc/foo
# Scale a replication controller identified by type and name specified in "foo-controller.yaml" to 3. # Scale a resource identified by type and name specified in "foo.yaml" to 3.
$ kubectl scale --replicas=3 -f foo-controller.yaml $ kubectl scale --replicas=3 -f foo.yaml
# If the replication controller named foo's current size is 2, scale foo to 3. # If the deployment named mysql's current size is 2, scale mysql to 3.
$ kubectl scale --current-replicas=2 --replicas=3 replicationcontrollers foo $ kubectl scale --current-replicas=2 --replicas=3 deployment/mysql
# Scale multiple replication controllers. # Scale multiple replication controllers.
$ kubectl scale --replicas=5 rc/foo rc/bar` $ kubectl scale --replicas=5 rc/foo rc/bar rc/baz
# Scale job named 'cron' to 3.
$ kubectl scale --replicas=3 job/cron`
) )
// NewCmdScale returns a cobra command with the appropriate configuration and flags to run scale // NewCmdScale returns a cobra command with the appropriate configuration and flags to run scale
...@@ -63,7 +66,7 @@ func NewCmdScale(f *cmdutil.Factory, out io.Writer) *cobra.Command { ...@@ -63,7 +66,7 @@ func NewCmdScale(f *cmdutil.Factory, out io.Writer) *cobra.Command {
Use: "scale [--resource-version=version] [--current-replicas=count] --replicas=COUNT (-f FILENAME | TYPE NAME)", Use: "scale [--resource-version=version] [--current-replicas=count] --replicas=COUNT (-f FILENAME | TYPE NAME)",
// resize is deprecated // resize is deprecated
Aliases: []string{"resize"}, Aliases: []string{"resize"},
Short: "Set a new size for a Replication Controller.", Short: "Set a new size for a Replication Controller, Job, or Deployment.",
Long: scale_long, Long: scale_long,
Example: scale_example, Example: scale_example,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
...@@ -74,13 +77,13 @@ func NewCmdScale(f *cmdutil.Factory, out io.Writer) *cobra.Command { ...@@ -74,13 +77,13 @@ func NewCmdScale(f *cmdutil.Factory, out io.Writer) *cobra.Command {
}, },
} }
cmd.Flags().String("resource-version", "", "Precondition for resource version. Requires that the current resource version match this value in order to scale.") cmd.Flags().String("resource-version", "", "Precondition for resource version. Requires that the current resource version match this value in order to scale.")
cmd.Flags().Int("current-replicas", -1, "Precondition for current size. Requires that the current size of the replication controller match this value in order to scale.") cmd.Flags().Int("current-replicas", -1, "Precondition for current size. Requires that the current size of the resource match this value in order to scale.")
cmd.Flags().Int("replicas", -1, "The new desired number of replicas. Required.") cmd.Flags().Int("replicas", -1, "The new desired number of replicas. Required.")
cmd.MarkFlagRequired("replicas") cmd.MarkFlagRequired("replicas")
cmd.Flags().Duration("timeout", 0, "The length of time to wait before giving up on a scale operation, zero means don't wait.") cmd.Flags().Duration("timeout", 0, "The length of time to wait before giving up on a scale operation, zero means don't wait.")
cmdutil.AddOutputFlagsForMutation(cmd) cmdutil.AddOutputFlagsForMutation(cmd)
usage := "Filename, directory, or URL to a file identifying the replication controller to set a new size" usage := "Filename, directory, or URL to a file identifying the resource to set a new size"
kubectl.AddJsonFilenameFlag(cmd, &options.Filenames, usage) kubectl.AddJsonFilenameFlag(cmd, &options.Filenames, usage)
return cmd return cmd
} }
...@@ -127,11 +130,11 @@ func RunScale(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri ...@@ -127,11 +130,11 @@ func RunScale(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri
resourceVersion := cmdutil.GetFlagString(cmd, "resource-version") resourceVersion := cmdutil.GetFlagString(cmd, "resource-version")
if len(resourceVersion) != 0 && len(infos) > 1 { if len(resourceVersion) != 0 && len(infos) > 1 {
return fmt.Errorf("cannot use --resource-version with multiple controllers") return fmt.Errorf("cannot use --resource-version with multiple resources")
} }
currentSize := cmdutil.GetFlagInt(cmd, "current-replicas") currentSize := cmdutil.GetFlagInt(cmd, "current-replicas")
if currentSize != -1 && len(infos) > 1 { if currentSize != -1 && len(infos) > 1 {
return fmt.Errorf("cannot use --current-replicas with multiple controllers") return fmt.Errorf("cannot use --current-replicas with multiple resources")
} }
precondition := &kubectl.ScalePrecondition{Size: currentSize, ResourceVersion: resourceVersion} precondition := &kubectl.ScalePrecondition{Size: currentSize, ResourceVersion: resourceVersion}
retry := kubectl.NewRetryParams(kubectl.Interval, kubectl.Timeout) retry := kubectl.NewRetryParams(kubectl.Interval, kubectl.Timeout)
......
...@@ -132,20 +132,7 @@ func (r *ScaleREST) Get(ctx api.Context, name string) (runtime.Object, error) { ...@@ -132,20 +132,7 @@ func (r *ScaleREST) Get(ctx api.Context, name string) (runtime.Object, error) {
if err != nil { if err != nil {
return nil, errors.NewNotFound("scale", name) return nil, errors.NewNotFound("scale", name)
} }
return &extensions.Scale{ return extensions.ScaleFromDeployment(deployment), nil
ObjectMeta: api.ObjectMeta{
Name: name,
Namespace: deployment.Namespace,
CreationTimestamp: deployment.CreationTimestamp,
},
Spec: extensions.ScaleSpec{
Replicas: deployment.Spec.Replicas,
},
Status: extensions.ScaleStatus{
Replicas: deployment.Status.Replicas,
Selector: deployment.Spec.Selector,
},
}, nil
} }
func (r *ScaleREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) { func (r *ScaleREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
...@@ -170,18 +157,5 @@ func (r *ScaleREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, ...@@ -170,18 +157,5 @@ func (r *ScaleREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object,
if err != nil { if err != nil {
return nil, false, errors.NewConflict("scale", scale.Name, err) return nil, false, errors.NewConflict("scale", scale.Name, err)
} }
return &extensions.Scale{ return extensions.ScaleFromDeployment(deployment), false, nil
ObjectMeta: api.ObjectMeta{
Name: deployment.Name,
Namespace: deployment.Namespace,
CreationTimestamp: deployment.CreationTimestamp,
},
Spec: extensions.ScaleSpec{
Replicas: deployment.Spec.Replicas,
},
Status: extensions.ScaleStatus{
Replicas: deployment.Status.Replicas,
Selector: deployment.Spec.Selector,
},
}, false, nil
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment