Skip to content
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

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions cmd/kops/scale.go
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)
}
130 changes: 130 additions & 0 deletions cmd/kops/scale_instancegroup.go
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
Copy link
Member

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!)

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
Copy link
Member

Choose a reason for hiding this comment

The 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"))
Copy link
Member

Choose a reason for hiding this comment

The 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 {
Copy link
Member

Choose a reason for hiding this comment

The 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
}
1 change: 1 addition & 0 deletions docs/cli/kops.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ kops helps you create, destroy, upgrade and maintain production-grade, highly av
* [kops import](kops_import.md) - Import a cluster.
* [kops replace](kops_replace.md) - Replace cluster resources.
* [kops rolling-update](kops_rolling-update.md) - Rolling update a cluster.
* [kops scale](kops_scale.md) - Scale instancegroups and other resources
* [kops toolbox](kops_toolbox.md) - Misc infrequently used commands.
* [kops update](kops_update.md) - Update a cluster.
* [kops upgrade](kops_upgrade.md) - Upgrade a kubernetes cluster.
Expand Down
38 changes: 38 additions & 0 deletions docs/cli/kops_scale.md
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

47 changes: 47 additions & 0 deletions docs/cli/kops_scale_ig.md
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

4 changes: 2 additions & 2 deletions pkg/apis/kops/instancegroup.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@ type InstanceGroupSpec struct {
// Image is the instance instance (ami etc) we should use
Image string `json:"image,omitempty"`
// MinSize is the minimum size of the pool
MinSize *int32 `json:"minSize,omitempty"`
MinSize *int32 `json:"minSize,omitempty"` // TODO change var type to int64 to folow aws-sdk/asg/Group
// MaxSize is the maximum size of the pool
MaxSize *int32 `json:"maxSize,omitempty"`
MaxSize *int32 `json:"maxSize,omitempty"` // TODO change var type to int64 to folow aws-sdk/asg/Group
// MachineType is the instance class
MachineType string `json:"machineType,omitempty"`
// RootVolumeSize is the size of the EBS root volume to use, in GB
Expand Down
5 changes: 3 additions & 2 deletions pkg/client/simple/clientset.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,15 @@ limitations under the License.
package simple

import (
"net/url"
"strings"
Copy link
Member

Choose a reason for hiding this comment

The 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 {
Expand Down
74 changes: 74 additions & 0 deletions pkg/instancegroups/instancegroups.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Copy link
Member

Choose a reason for hiding this comment

The 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)
Copy link
Member

Choose a reason for hiding this comment

The 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
}