-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add scale instancegroup command #2765
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
/* | ||
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 main | ||
|
||
import ( | ||
"github.com/spf13/cobra" | ||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates" | ||
"k8s.io/kubernetes/pkg/util/i18n" | ||
) | ||
|
||
var ( | ||
//TODO add comments | ||
scale_long = templates.LongDesc(i18n.T(`Scale resources in/out | ||
`)) | ||
|
||
scale_example = templates.Examples(i18n.T(`kops scale ig --name $NAME nodes --replicas=2 | ||
kops scale ig --name $NAME nodes --replicas=0 | ||
`)) | ||
) | ||
|
||
var scaleCmd = &cobra.Command{ | ||
Use: "scale", | ||
Short: i18n.T(`Scale instancegroups and other resources`), | ||
Long: scale_long, | ||
Example: scale_example, | ||
} | ||
|
||
func init() { | ||
rootCommand.AddCommand(scaleCmd) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
/* | ||
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 main | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/golang/glog" | ||
"github.com/spf13/cobra" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/kops/pkg/instancegroups" | ||
"k8s.io/kops/upup/pkg/fi/cloudup" | ||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates" | ||
"k8s.io/kubernetes/pkg/util/i18n" | ||
) | ||
|
||
type ScaleIgCmd struct { | ||
Yes bool | ||
Replicas int64 | ||
} | ||
|
||
const ( | ||
defReplicas = -1 | ||
) | ||
|
||
// TODO add ability to add-nodes rather than scale | ||
var ( | ||
//TODO add comments | ||
scale_instancegroup_long = templates.LongDesc(i18n.T(` | ||
long description... | ||
`)) | ||
|
||
scale_instancegroup_example = templates.Examples(i18n.T(` | ||
# Scale a ig fixing it to 2 replicas | ||
kops scale ig --name cluster.kops.ddy.systems nodes --replicas=2 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Either $NAME or cluster.example.com |
||
|
||
`)) | ||
) | ||
|
||
var scaleIg ScaleIgCmd | ||
|
||
func init() { | ||
|
||
cmd := &cobra.Command{ | ||
Use: "ig", | ||
Aliases: []string{"instancegroup", "instancegroups"}, | ||
Short: i18n.T("Scale instances instancegroups"), | ||
Long: scale_instancegroup_long, | ||
Example: scale_instancegroup_example, | ||
Run: func(cmd *cobra.Command, args []string) { | ||
|
||
if len(args) == 0 { | ||
exitWithError(fmt.Errorf("Specify name of instance group to edit")) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: probably should scale "to scale" |
||
} | ||
|
||
if len(args) != 1 { | ||
exitWithError(fmt.Errorf("Can only specify one instance group at a time")) | ||
} | ||
|
||
err := scaleIg.Run(args) | ||
if err != nil { | ||
exitWithError(err) | ||
} | ||
}, | ||
} | ||
|
||
cmd.Flags().Int64Var(&scaleIg.Replicas, "replicas", defReplicas, i18n.T("The new desired number of replicas. Required.")) | ||
|
||
scaleCmd.AddCommand(cmd) | ||
} | ||
func (c *ScaleIgCmd) Run(args []string) error { | ||
|
||
groupName := args[0] | ||
|
||
cluster, err := rootCommand.Cluster() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if groupName == "" { | ||
return fmt.Errorf("name is required") | ||
} | ||
|
||
if c.Replicas == defReplicas { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: It's probably better to use the Changed field on the flag (doing this in the cobra.Command Run function instead) (spf13/cobra#23). The reason being that then the -1 default value won't appear in the help! |
||
return fmt.Errorf("argument --replicas is required") | ||
} | ||
|
||
clientset, err := rootCommand.Clientset() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
igGroup, err := clientset.InstanceGroupsFor(cluster).Get(groupName, metav1.GetOptions{}) | ||
if err != nil { | ||
return fmt.Errorf("error reading InstanceGroup %q: %v", groupName, err) | ||
} | ||
if igGroup == nil { | ||
return fmt.Errorf("InstanceGroup %q not found", groupName) | ||
} | ||
|
||
cloud, err := cloudup.BuildCloud(cluster) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
s := &instancegroups.ScaleInstanceGroup{Cluster: cluster, Cloud: cloud, | ||
Clientset: clientset, DesiredReplicas: c.Replicas} | ||
|
||
if err = s.ScaleInstanceGroup(igGroup); err != nil { | ||
return err | ||
} | ||
|
||
glog.Infof("Successful scaled! It will take few minutes to complete this operation...") | ||
|
||
return nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
|
||
<!--- This file is automatically generated by make gen-cli-docs; changes should be made in the go CLI command code (under cmd/kops) --> | ||
|
||
## kops scale | ||
|
||
Scale instancegroups and other resources | ||
|
||
### Synopsis | ||
|
||
|
||
Scale resources in/out | ||
|
||
### Examples | ||
|
||
``` | ||
kops scale ig --name $NAME nodes --replicas=2 | ||
kops scale ig --name $NAME nodes --replicas=0 | ||
``` | ||
|
||
### Options inherited from parent commands | ||
|
||
``` | ||
--alsologtostderr log to standard error as well as files | ||
--config string config file (default is $HOME/.kops.yaml) | ||
--log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0) | ||
--log_dir string If non-empty, write log files in this directory | ||
--logtostderr log to standard error instead of files (default false) | ||
--name string Name of cluster | ||
--state string Location of state storage | ||
--stderrthreshold severity logs at or above this threshold go to stderr (default 2) | ||
-v, --v Level log level for V logs | ||
--vmodule moduleSpec comma-separated list of pattern=N settings for file-filtered logging | ||
``` | ||
|
||
### SEE ALSO | ||
* [kops](kops.md) - kops is Kubernetes ops. | ||
* [kops scale ig](kops_scale_ig.md) - Scale instances instancegroups | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
|
||
<!--- This file is automatically generated by make gen-cli-docs; changes should be made in the go CLI command code (under cmd/kops) --> | ||
|
||
## kops scale ig | ||
|
||
Scale instances instancegroups | ||
|
||
### Synopsis | ||
|
||
|
||
long description... | ||
|
||
``` | ||
kops scale ig | ||
``` | ||
|
||
### Examples | ||
|
||
``` | ||
# Scale a ig fixing it to 2 replicas | ||
kops scale ig --name cluster.kops.ddy.systems nodes --replicas=2 | ||
``` | ||
|
||
### Options | ||
|
||
``` | ||
--replicas int The new desired number of replicas. Required. (default -1) | ||
``` | ||
|
||
### Options inherited from parent commands | ||
|
||
``` | ||
--alsologtostderr log to standard error as well as files | ||
--config string config file (default is $HOME/.kops.yaml) | ||
--log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0) | ||
--log_dir string If non-empty, write log files in this directory | ||
--logtostderr log to standard error instead of files (default false) | ||
--name string Name of cluster | ||
--state string Location of state storage | ||
--stderrthreshold severity logs at or above this threshold go to stderr (default 2) | ||
-v, --v Level log level for V logs | ||
--vmodule moduleSpec comma-separated list of pattern=N settings for file-filtered logging | ||
``` | ||
|
||
### SEE ALSO | ||
* [kops scale](kops_scale.md) - Scale instancegroups and other resources | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,14 +17,15 @@ limitations under the License. | |
package simple | ||
|
||
import ( | ||
"net/url" | ||
"strings" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is what triggered the rebase requirement! |
||
|
||
"github.com/golang/glog" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/kops/pkg/apis/kops" | ||
"k8s.io/kops/pkg/apis/kops/validation" | ||
kopsinternalversion "k8s.io/kops/pkg/client/clientset_generated/clientset/typed/kops/internalversion" | ||
"k8s.io/kops/util/pkg/vfs" | ||
"net/url" | ||
"strings" | ||
) | ||
|
||
type Clientset interface { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -468,3 +468,77 @@ func (g *CloudInstanceGroup) Delete(cloud fi.Cloud) error { | |
|
||
return nil | ||
} | ||
|
||
// ScaleInstanceGroup scale the cloud resources for an InstanceGroup | ||
type ScaleInstanceGroup struct { | ||
Cluster *api.Cluster | ||
Cloud fi.Cloud | ||
DesiredReplicas int64 | ||
|
||
Clientset simple.Clientset | ||
} | ||
|
||
func (c *ScaleInstanceGroup) ScaleInstanceGroup(group *api.InstanceGroup) error { | ||
groups, err := FindCloudInstanceGroups(c.Cloud, c.Cluster, []*api.InstanceGroup{group}, false, nil) | ||
cig := groups[group.ObjectMeta.Name] | ||
|
||
if cig == nil { | ||
return fmt.Errorf("AutoScalingGroup %q not found in cloud - skipping scaling", group.ObjectMeta.Name) | ||
} | ||
|
||
if len(groups) != 1 { | ||
return fmt.Errorf("Multiple InstanceGroup resources found in cloud") | ||
} | ||
|
||
cig.asg.DesiredCapacity = &c.DesiredReplicas | ||
glog.Infof("Scaling InstanceGroup %q instances size to: %v", group.ObjectMeta.Name, c.DesiredReplicas) | ||
|
||
// decrease max cluster size | ||
if c.DesiredReplicas < *cig.asg.MinSize { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah - tricky! I'm thinking we should just set min and max both to the desired size. If you disagree, can you add a comment (here or in the code) to explain? |
||
glog.Infof("Changing min instances from %v to %v", *cig.asg.MinSize, c.DesiredReplicas) | ||
cig.asg.MinSize = &c.DesiredReplicas | ||
group.Spec.MinSize = fi.Int32(int32(c.DesiredReplicas)) | ||
} | ||
|
||
// increasing max cluster size | ||
if c.DesiredReplicas > *cig.asg.MaxSize { | ||
glog.Infof("Changing max instances from %v to %v", *cig.asg.MaxSize, c.DesiredReplicas) | ||
cig.asg.MaxSize = &c.DesiredReplicas | ||
group.Spec.MaxSize = fi.Int32(int32(c.DesiredReplicas)) | ||
} | ||
|
||
err = cig.Scale(c.Cloud) | ||
if err != nil { | ||
return fmt.Errorf("error scaling InstanceGroup: %v", err) | ||
} | ||
|
||
_, err = c.Clientset.InstanceGroupsFor(c.Cluster).Update(group) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (g *CloudInstanceGroup) Scale(cloud fi.Cloud) error { | ||
|
||
c := cloud.(awsup.AWSCloud) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I worry we might have broken this with some of the refactorings of this interface that have gone in recently... it should be easier now, but let me know if you need some pointers figuring out where things have moved to! |
||
// TODO add warning about cluster autoscaling and replicas | ||
{ | ||
asgName := aws.StringValue(g.asg.AutoScalingGroupName) | ||
request := &autoscaling.UpdateAutoScalingGroupInput{ | ||
AutoScalingGroupName: g.asg.AutoScalingGroupName, | ||
DesiredCapacity: g.asg.DesiredCapacity, | ||
MaxSize: g.asg.MaxSize, | ||
MinSize: g.asg.MinSize, | ||
} | ||
_, err := c.Autoscaling().UpdateAutoScalingGroup(request) | ||
|
||
if err != nil { | ||
return fmt.Errorf("error scaling autoscaling group %q: %v", asgName, err) | ||
} | ||
|
||
} | ||
|
||
return nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would this be like
kops scale ig nodes +2
? That would indeed be cool (but let's get this PR merged!)