Skip to content

Commit

Permalink
Merge pull request kubernetes#2822 from austinmoore-/fix_1808
Browse files Browse the repository at this point in the history
Add field to enable EBS Volume Optimization
  • Loading branch information
justinsb authored Jul 1, 2017
2 parents a60a4cc + 6ec6470 commit 462e203
Show file tree
Hide file tree
Showing 9 changed files with 129 additions and 2 deletions.
9 changes: 9 additions & 0 deletions docs/instance_groups.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,3 +186,12 @@ Example: `kops delete ig morenodes`

No rolling-update is needed (and note this is not currently graceful, so there may be interruptions to
workloads where the pods are running on those nodes).

## EBS Volume Optimization

EBS-Optimized instances can be created by setting the following field:

```
spec:
rootVolumeOptimization: true
```
2 changes: 2 additions & 0 deletions pkg/apis/kops/instancegroup.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ type InstanceGroupSpec struct {
RootVolumeSize *int32 `json:"rootVolumeSize,omitempty"`
// RootVolumeType is the type of the EBS root volume to use (e.g. gp2)
RootVolumeType *string `json:"rootVolumeType,omitempty"`
// RootVolumeOptimization enables EBS optimization for an instance
RootVolumeOptimization *bool `json:"rootVolumeOptimization,omitempty"`

Subnets []string `json:"subnets,omitempty"`

Expand Down
2 changes: 2 additions & 0 deletions pkg/apis/kops/v1alpha1/instancegroup.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ type InstanceGroupSpec struct {
RootVolumeSize *int32 `json:"rootVolumeSize,omitempty"`
// RootVolumeType is the type of the EBS root volume to use (e.g. gp2)
RootVolumeType *string `json:"rootVolumeType,omitempty"`
// RootVolumeOptimization enables EBS optimization for an instance
RootVolumeOptimization *bool `json:"rootVolumeOptimization,omitempty"`

Zones []string `json:"zones,omitempty"`

Expand Down
2 changes: 2 additions & 0 deletions pkg/apis/kops/v1alpha1/zz_generated.conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -1122,6 +1122,7 @@ func autoConvert_v1alpha1_InstanceGroupSpec_To_kops_InstanceGroupSpec(in *Instan
out.MachineType = in.MachineType
out.RootVolumeSize = in.RootVolumeSize
out.RootVolumeType = in.RootVolumeType
out.RootVolumeOptimization = in.RootVolumeOptimization
// WARNING: in.Zones requires manual conversion: does not exist in peer-type
out.MaxPrice = in.MaxPrice
out.AssociatePublicIP = in.AssociatePublicIP
Expand Down Expand Up @@ -1150,6 +1151,7 @@ func autoConvert_kops_InstanceGroupSpec_To_v1alpha1_InstanceGroupSpec(in *kops.I
out.MachineType = in.MachineType
out.RootVolumeSize = in.RootVolumeSize
out.RootVolumeType = in.RootVolumeType
out.RootVolumeOptimization = in.RootVolumeOptimization
// WARNING: in.Subnets requires manual conversion: does not exist in peer-type
out.MaxPrice = in.MaxPrice
out.AssociatePublicIP = in.AssociatePublicIP
Expand Down
2 changes: 2 additions & 0 deletions pkg/apis/kops/v1alpha2/instancegroup.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ type InstanceGroupSpec struct {
RootVolumeSize *int32 `json:"rootVolumeSize,omitempty"`
// RootVolumeType is the type of the EBS root volume to use (e.g. gp2)
RootVolumeType *string `json:"rootVolumeType,omitempty"`
// RootVolumeOptimization enables EBS optimization for an instance
RootVolumeOptimization *bool `json:"rootVolumeOptimization,omitempty"`

Subnets []string `json:"subnets,omitempty"`

Expand Down
2 changes: 2 additions & 0 deletions pkg/apis/kops/v1alpha2/zz_generated.conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -1212,6 +1212,7 @@ func autoConvert_v1alpha2_InstanceGroupSpec_To_kops_InstanceGroupSpec(in *Instan
out.MachineType = in.MachineType
out.RootVolumeSize = in.RootVolumeSize
out.RootVolumeType = in.RootVolumeType
out.RootVolumeOptimization = in.RootVolumeOptimization
out.Subnets = in.Subnets
out.MaxPrice = in.MaxPrice
out.AssociatePublicIP = in.AssociatePublicIP
Expand Down Expand Up @@ -1244,6 +1245,7 @@ func autoConvert_kops_InstanceGroupSpec_To_v1alpha2_InstanceGroupSpec(in *kops.I
out.MachineType = in.MachineType
out.RootVolumeSize = in.RootVolumeSize
out.RootVolumeType = in.RootVolumeType
out.RootVolumeOptimization = in.RootVolumeOptimization
out.Subnets = in.Subnets
out.MaxPrice = in.MaxPrice
out.AssociatePublicIP = in.AssociatePublicIP
Expand Down
5 changes: 3 additions & 2 deletions pkg/model/awsmodel/autoscalinggroup.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,9 @@ func (b *AutoscalingGroupModelBuilder) Build(c *fi.ModelBuilderContext) error {
ImageID: s(ig.Spec.Image),
InstanceType: s(ig.Spec.MachineType),

RootVolumeSize: i64(int64(volumeSize)),
RootVolumeType: s(volumeType),
RootVolumeSize: i64(int64(volumeSize)),
RootVolumeType: s(volumeType),
RootVolumeOptimization: ig.Spec.RootVolumeOptimization,
}

if ig.Spec.Tenancy != "" {
Expand Down
98 changes: 98 additions & 0 deletions pkg/model/awsmodel/autoscalinggroup_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
Copyright 2017 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 awsmodel

import (
"k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/model"
"k8s.io/kops/upup/pkg/fi"
"k8s.io/kops/upup/pkg/fi/cloudup/awstasks"
"testing"
)

func buildMinimalCluster() *kops.Cluster {
c := &kops.Cluster{}
c.ObjectMeta.Name = "testcluster.test.com"
c.Spec.KubernetesVersion = "1.4.6"
c.Spec.Subnets = []kops.ClusterSubnetSpec{
{Name: "subnet-us-mock-1a", Zone: "us-mock-1a", CIDR: "172.20.1.0/24", Type: kops.SubnetTypePrivate},
}

c.Spec.KubernetesAPIAccess = []string{"0.0.0.0/0"}
c.Spec.SSHAccess = []string{"0.0.0.0/0"}

// Default to public topology
c.Spec.Topology = &kops.TopologySpec{
Masters: kops.TopologyPublic,
Nodes: kops.TopologyPublic,
}
c.Spec.NetworkCIDR = "172.20.0.0/16"
c.Spec.NonMasqueradeCIDR = "100.64.0.0/10"
c.Spec.CloudProvider = "aws"

c.Spec.ConfigBase = "s3://unittest-bucket/"

// Required to stop a call to cloud provider
// TODO: Mock cloudprovider
c.Spec.DNSZone = "test.com"

return c
}

func buildNodeInstanceGroup(subnets ...string) *kops.InstanceGroup {
g := &kops.InstanceGroup{}
g.ObjectMeta.Name = "nodes"
g.Spec.Role = kops.InstanceGroupRoleNode
g.Spec.Subnets = subnets

return g
}

// Tests that RootVolumeOptimization flag gets added to the awstasks
func TestRootVolumeOptimizationFlag(t *testing.T) {
cluster := buildMinimalCluster()
ig := buildNodeInstanceGroup("subnet-us-mock-1a")
ig.Spec.RootVolumeOptimization = fi.Bool(true)

k := [][]byte{}
k = append(k, []byte("ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCySdqIU+FhCWl3BNrAvPaOe5VfL2aCARUWwy91ZP+T7LBwFa9lhdttfjp/VX1D1/PVwntn2EhN079m8c2kfdmiZ/iCHqrLyIGSd+BOiCz0lT47znvANSfxYjLUuKrWWWeaXqerJkOsAD4PHchRLbZGPdbfoBKwtb/WT4GMRQmb9vmiaZYjsfdPPM9KkWI9ECoWFGjGehA8D+iYIPR711kRacb1xdYmnjHqxAZHFsb5L8wDWIeAyhy49cBD+lbzTiioq2xWLorXuFmXh6Do89PgzvHeyCLY6816f/kCX6wIFts8A2eaEHFL4rAOsuh6qHmSxGCR9peSyuRW8DxV725x justin@test"))

igs := []*kops.InstanceGroup{}
igs = append(igs, ig)

b := AutoscalingGroupModelBuilder{
AWSModelContext: &AWSModelContext{
KopsModelContext: &model.KopsModelContext{
SSHPublicKeys: k,
Cluster: cluster,
InstanceGroups: igs,
},
},
}

c := &fi.ModelBuilderContext{
Tasks: make(map[string]fi.Task),
}

b.Build(c)

lc := c.Tasks["LaunchConfiguration/nodes.testcluster.test.com"].(*awstasks.LaunchConfiguration)

if *lc.RootVolumeOptimization == false {
t.Fatalf("RootVolumeOptimization was expected to be true, but was false")
}
}
9 changes: 9 additions & 0 deletions upup/pkg/fi/cloudup/awstasks/launchconfiguration.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ type LaunchConfiguration struct {
RootVolumeSize *int64
// RootVolumeType is the type of the EBS root volume to use (e.g. gp2)
RootVolumeType *string
// RootVolumeOptimization enables EBS optimization for an instance
RootVolumeOptimization *bool

// SpotPrice is set to the spot-price bid if this is a spot pricing request
SpotPrice string
Expand Down Expand Up @@ -246,6 +248,7 @@ func (_ *LaunchConfiguration) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *La
request.LaunchConfigurationName = &launchConfigurationName
request.ImageId = image.ImageId
request.InstanceType = e.InstanceType
request.EbsOptimized = e.RootVolumeOptimization

if e.SSHKey != nil {
request.KeyName = e.SSHKey.Name
Expand Down Expand Up @@ -341,6 +344,7 @@ type terraformLaunchConfiguration struct {
AssociatePublicIpAddress *bool `json:"associate_public_ip_address,omitempty"`
UserData *terraform.Literal `json:"user_data,omitempty"`
RootBlockDevice *terraformBlockDevice `json:"root_block_device,omitempty"`
EBSOptimized *bool `json:"ebs_optimized,omitempty"`
EphemeralBlockDevice []*terraformBlockDevice `json:"ephemeral_block_device,omitempty"`
Lifecycle *terraform.Lifecycle `json:"lifecycle,omitempty"`
SpotPrice *string `json:"spot_price,omitempty"`
Expand Down Expand Up @@ -393,6 +397,8 @@ func (_ *LaunchConfiguration) RenderTerraform(t *terraform.TerraformTarget, a, e

tf.AssociatePublicIpAddress = e.AssociatePublicIP

tf.EBSOptimized = e.RootVolumeOptimization

{
rootDevices, err := e.buildRootDevice(cloud)
if err != nil {
Expand Down Expand Up @@ -453,6 +459,7 @@ func (e *LaunchConfiguration) TerraformLink() *terraform.Literal {
type cloudformationLaunchConfiguration struct {
AssociatePublicIpAddress *bool `json:"AssociatePublicIpAddress,omitempty"`
BlockDeviceMappings []*cloudformationBlockDevice `json:"BlockDeviceMappings,omitempty"`
EBSOptimized *bool `json:"EbsOptimized,omitempty"`
IAMInstanceProfile *cloudformation.Literal `json:"IamInstanceProfile,omitempty"`
ImageID *string `json:"ImageId,omitempty"`
InstanceType *string `json:"InstanceType,omitempty"`
Expand Down Expand Up @@ -518,6 +525,8 @@ func (_ *LaunchConfiguration) RenderCloudformation(t *cloudformation.Cloudformat
}
cf.AssociatePublicIpAddress = e.AssociatePublicIP

cf.EBSOptimized = e.RootVolumeOptimization

{
rootDevices, err := e.buildRootDevice(cloud)
if err != nil {
Expand Down

0 comments on commit 462e203

Please sign in to comment.