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

Added EBS IO2 volumeType support to Managed NodeGroup #7989

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
15 changes: 9 additions & 6 deletions pkg/apis/eksctl.io/v1alpha5/assets/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1580,13 +1580,14 @@
},
"volumeType": {
"type": "string",
"description": "Valid variants are: `\"gp2\"` is General Purpose SSD, `\"gp3\"` is General Purpose SSD which can be optimised for high throughput (default), `\"io1\"` is Provisioned IOPS SSD, `\"sc1\"` is Cold HDD, `\"st1\"` is Throughput Optimized HDD.",
"x-intellij-html-description": "Valid variants are: <code>&quot;gp2&quot;</code> is General Purpose SSD, <code>&quot;gp3&quot;</code> is General Purpose SSD which can be optimised for high throughput (default), <code>&quot;io1&quot;</code> is Provisioned IOPS SSD, <code>&quot;sc1&quot;</code> is Cold HDD, <code>&quot;st1&quot;</code> is Throughput Optimized HDD.",
"description": "Valid variants are: `\"gp2\"` is General Purpose SSD, `\"gp3\"` is General Purpose SSD which can be optimised for high throughput (default), `\"io1\"` is Provisioned IOPS SSD, `\"io2\"` is Provisioned IOPS SSD, `\"sc1\"` is Cold HDD, `\"st1\"` is Throughput Optimized HDD.",
"x-intellij-html-description": "Valid variants are: <code>&quot;gp2&quot;</code> is General Purpose SSD, <code>&quot;gp3&quot;</code> is General Purpose SSD which can be optimised for high throughput (default), <code>&quot;io1&quot;</code> is Provisioned IOPS SSD, <code>&quot;io2&quot;</code> is Provisioned IOPS SSD, <code>&quot;sc1&quot;</code> is Cold HDD, <code>&quot;st1&quot;</code> is Throughput Optimized HDD.",
"default": "gp3",
"enum": [
"gp2",
"gp3",
"io1",
"io2",
"sc1",
"st1"
]
Expand Down Expand Up @@ -1947,13 +1948,14 @@
},
"volumeType": {
"type": "string",
"description": "Valid variants are: `\"gp2\"` is General Purpose SSD, `\"gp3\"` is General Purpose SSD which can be optimised for high throughput (default), `\"io1\"` is Provisioned IOPS SSD, `\"sc1\"` is Cold HDD, `\"st1\"` is Throughput Optimized HDD.",
"x-intellij-html-description": "Valid variants are: <code>&quot;gp2&quot;</code> is General Purpose SSD, <code>&quot;gp3&quot;</code> is General Purpose SSD which can be optimised for high throughput (default), <code>&quot;io1&quot;</code> is Provisioned IOPS SSD, <code>&quot;sc1&quot;</code> is Cold HDD, <code>&quot;st1&quot;</code> is Throughput Optimized HDD.",
"description": "Valid variants are: `\"gp2\"` is General Purpose SSD, `\"gp3\"` is General Purpose SSD which can be optimised for high throughput (default), `\"io1\"` is Provisioned IOPS SSD, `\"io2\"` is Provisioned IOPS SSD, `\"sc1\"` is Cold HDD, `\"st1\"` is Throughput Optimized HDD.",
"x-intellij-html-description": "Valid variants are: <code>&quot;gp2&quot;</code> is General Purpose SSD, <code>&quot;gp3&quot;</code> is General Purpose SSD which can be optimised for high throughput (default), <code>&quot;io1&quot;</code> is Provisioned IOPS SSD, <code>&quot;io2&quot;</code> is Provisioned IOPS SSD, <code>&quot;sc1&quot;</code> is Cold HDD, <code>&quot;st1&quot;</code> is Throughput Optimized HDD.",
"default": "gp3",
"enum": [
"gp2",
"gp3",
"io1",
"io2",
"sc1",
"st1"
]
Expand Down Expand Up @@ -2656,13 +2658,14 @@
},
"volumeType": {
"type": "string",
"description": "Valid variants are: `\"gp2\"` is General Purpose SSD, `\"gp3\"` is General Purpose SSD which can be optimised for high throughput (default), `\"io1\"` is Provisioned IOPS SSD, `\"sc1\"` is Cold HDD, `\"st1\"` is Throughput Optimized HDD.",
"x-intellij-html-description": "Valid variants are: <code>&quot;gp2&quot;</code> is General Purpose SSD, <code>&quot;gp3&quot;</code> is General Purpose SSD which can be optimised for high throughput (default), <code>&quot;io1&quot;</code> is Provisioned IOPS SSD, <code>&quot;sc1&quot;</code> is Cold HDD, <code>&quot;st1&quot;</code> is Throughput Optimized HDD.",
"description": "Valid variants are: `\"gp2\"` is General Purpose SSD, `\"gp3\"` is General Purpose SSD which can be optimised for high throughput (default), `\"io1\"` is Provisioned IOPS SSD, `\"io2\"` is Provisioned IOPS SSD, `\"sc1\"` is Cold HDD, `\"st1\"` is Throughput Optimized HDD.",
"x-intellij-html-description": "Valid variants are: <code>&quot;gp2&quot;</code> is General Purpose SSD, <code>&quot;gp3&quot;</code> is General Purpose SSD which can be optimised for high throughput (default), <code>&quot;io1&quot;</code> is Provisioned IOPS SSD, <code>&quot;io2&quot;</code> is Provisioned IOPS SSD, <code>&quot;sc1&quot;</code> is Cold HDD, <code>&quot;st1&quot;</code> is Throughput Optimized HDD.",
"default": "gp3",
"enum": [
"gp2",
"gp3",
"io1",
"io2",
"sc1",
"st1"
]
Expand Down
7 changes: 7 additions & 0 deletions pkg/apis/eksctl.io/v1alpha5/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,10 @@ func setVolumeDefaults(ng *NodeGroupBase, controlPlaneOnOutposts bool, template
if ng.VolumeIOPS == nil {
ng.VolumeIOPS = aws.Int(DefaultNodeVolumeIO1IOPS)
}
case NodeVolumeTypeIO2:
if ng.VolumeIOPS == nil {
ng.VolumeIOPS = aws.Int(DefaultNodeVolumeIO2IOPS)
}
}

if ng.AMIFamily == NodeImageFamilyBottlerocket && !IsSetAndNonEmptyString(ng.VolumeName) {
Expand Down Expand Up @@ -254,6 +258,9 @@ func setDefaultsForAdditionalVolumes(ng *NodeGroupBase, controlPlaneOnOutposts b
if *av.VolumeType == NodeVolumeTypeIO1 && av.VolumeIOPS == nil {
ng.AdditionalVolumes[i].VolumeIOPS = aws.Int(DefaultNodeVolumeIO1IOPS)
}
if *av.VolumeType == NodeVolumeTypeIO2 && av.VolumeIOPS == nil {
ng.AdditionalVolumes[i].VolumeIOPS = aws.Int(DefaultNodeVolumeIO2IOPS)
}
}
}

Expand Down
1 change: 1 addition & 0 deletions pkg/apis/eksctl.io/v1alpha5/outposts_validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,7 @@ var _ = Describe("Outposts validation", func() {
},
Entry(api.NodeVolumeTypeGP3, api.NodeVolumeTypeGP3, true),
Entry(api.NodeVolumeTypeIO1, api.NodeVolumeTypeIO1, true),
Entry(api.NodeVolumeTypeIO2, api.NodeVolumeTypeIO2, true),
Entry(api.NodeVolumeTypeSC1, api.NodeVolumeTypeSC1, true),
Entry(api.NodeVolumeTypeST1, api.NodeVolumeTypeST1, true),
Entry(api.NodeVolumeTypeGP2, api.NodeVolumeTypeGP2, false),
Expand Down
5 changes: 5 additions & 0 deletions pkg/apis/eksctl.io/v1alpha5/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,8 @@ const (
NodeVolumeTypeGP3 = "gp3"
// NodeVolumeTypeIO1 is Provisioned IOPS SSD
NodeVolumeTypeIO1 = "io1"
// NodeVolumeTypeIO2 is Provisioned IOPS SSD
NodeVolumeTypeIO2 = "io2"
// NodeVolumeTypeSC1 is Cold HDD
NodeVolumeTypeSC1 = "sc1"
// NodeVolumeTypeST1 is Throughput Optimized HDD
Expand All @@ -431,6 +433,8 @@ const (
DefaultNodeVolumeThroughput = 125
// DefaultNodeVolumeIO1IOPS defines the default throughput for io1 volumes, set to the min value
DefaultNodeVolumeIO1IOPS = 100
// DefaultNodeVolumeIO2IOPS defines the default throughput for io2 volumes, set to the min value
DefaultNodeVolumeIO2IOPS = 100
// DefaultNodeVolumeGP3IOPS defines the default throughput for gp3, set to the min value
DefaultNodeVolumeGP3IOPS = 3000
)
Expand Down Expand Up @@ -605,6 +609,7 @@ func SupportedNodeVolumeTypes() []string {
NodeVolumeTypeGP2,
NodeVolumeTypeGP3,
NodeVolumeTypeIO1,
NodeVolumeTypeIO2,
NodeVolumeTypeSC1,
NodeVolumeTypeST1,
}
Expand Down
12 changes: 10 additions & 2 deletions pkg/apis/eksctl.io/v1alpha5/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ const (
MaxThroughput = 1000
MinIO1Iops = DefaultNodeVolumeIO1IOPS
MaxIO1Iops = 64000
MinIO2Iops = DefaultNodeVolumeIO2IOPS
MaxIO2Iops = 256000
MinGP3Iops = DefaultNodeVolumeGP3IOPS
MaxGP3Iops = 16000
OneDay = 86400
Expand Down Expand Up @@ -784,8 +786,8 @@ func validateNodeGroupBase(np NodePool, path string, controlPlaneOnOutposts bool
func validateVolumeOpts(ng *NodeGroupBase, path string, controlPlaneOnOutposts bool) error {
if ng.VolumeType != nil {
volumeType := *ng.VolumeType
if ng.VolumeIOPS != nil && !(volumeType == NodeVolumeTypeIO1 || volumeType == NodeVolumeTypeGP3) {
return fmt.Errorf("%s.volumeIOPS is only supported for %s and %s volume types", path, NodeVolumeTypeIO1, NodeVolumeTypeGP3)
if ng.VolumeIOPS != nil && !(volumeType == NodeVolumeTypeIO1 || volumeType == NodeVolumeTypeIO2 || volumeType == NodeVolumeTypeGP3) {
return fmt.Errorf("%s.volumeIOPS is only supported for %s, %s and %s volume types", path, NodeVolumeTypeIO1, NodeVolumeTypeIO2, NodeVolumeTypeGP3)
}

if volumeType == NodeVolumeTypeIO1 {
Expand All @@ -794,6 +796,12 @@ func validateVolumeOpts(ng *NodeGroupBase, path string, controlPlaneOnOutposts b
}
}

if volumeType == NodeVolumeTypeIO2 {
if ng.VolumeIOPS != nil && !(*ng.VolumeIOPS >= MinIO2Iops && *ng.VolumeIOPS <= MaxIO2Iops) {
return fmt.Errorf("value for %s.volumeIOPS must be within range %d-%d", path, MinIO2Iops, MaxIO2Iops)
}
}

if ng.VolumeThroughput != nil && volumeType != NodeVolumeTypeGP3 {
return fmt.Errorf("%s.volumeThroughput is only supported for %s volume type", path, NodeVolumeTypeGP3)
}
Expand Down
26 changes: 25 additions & 1 deletion pkg/apis/eksctl.io/v1alpha5/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,10 +307,34 @@ var _ = Describe("ClusterConfig validation", func() {
})
})

When("VolumeType is io2", func() {
BeforeEach(func() {
*ng0.VolumeType = api.NodeVolumeTypeIO2
})

It("does not fail", func() {
Expect(api.ValidateNodeGroup(0, ng0, cfg)).To(Succeed())
})

When(fmt.Sprintf("the value of volumeIOPS is < %d", api.MinIO2Iops), func() {
It("returns an error", func() {
ng0.VolumeIOPS = aws.Int(api.MinIO2Iops - 1)
Expect(api.ValidateNodeGroup(0, ng0, cfg)).To(MatchError("value for nodeGroups[0].volumeIOPS must be within range 100-256000"))
})
})

When(fmt.Sprintf("the value of volumeIOPS is > %d", api.MaxIO2Iops), func() {
It("returns an error", func() {
ng0.VolumeIOPS = aws.Int(api.MaxIO2Iops + 1)
Expect(api.ValidateNodeGroup(0, ng0, cfg)).To(MatchError("value for nodeGroups[0].volumeIOPS must be within range 100-256000"))
})
})
})

When("VolumeType is one for which IOPS is not supported", func() {
It("returns an error", func() {
*ng0.VolumeType = api.NodeVolumeTypeGP2
Expect(api.ValidateNodeGroup(0, ng0, cfg)).To(MatchError("nodeGroups[0].volumeIOPS is only supported for io1 and gp3 volume types"))
Expect(api.ValidateNodeGroup(0, ng0, cfg)).To(MatchError("nodeGroups[0].volumeIOPS is only supported for io1, io2 and gp3 volume types"))
})
})
})
Expand Down
2 changes: 1 addition & 1 deletion pkg/cfn/builder/block_device_mapping.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func makeBlockDeviceMapping(vm *api.VolumeMapping) *gfnec2.LaunchTemplate_BlockD
mapping.Ebs.KmsKeyId = gfnt.NewString(*vm.VolumeKmsKeyID)
}

if (*vm.VolumeType == api.NodeVolumeTypeIO1 || *vm.VolumeType == api.NodeVolumeTypeGP3) && vm.VolumeIOPS != nil {
if (*vm.VolumeType == api.NodeVolumeTypeIO1 || *vm.VolumeType == api.NodeVolumeTypeIO2 || *vm.VolumeType == api.NodeVolumeTypeGP3) && vm.VolumeIOPS != nil {
mapping.Ebs.Iops = gfnt.NewInteger(*vm.VolumeIOPS)
}

Expand Down
12 changes: 12 additions & 0 deletions pkg/cfn/builder/nodegroup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1204,6 +1204,18 @@ var _ = Describe("Unmanaged NodeGroup Template Builder", func() {
})
})

Context("ng.VolumeType is IO2", func() {
BeforeEach(func() {
ng.VolumeType = aws.String(api.NodeVolumeTypeIO1)
ng.VolumeIOPS = aws.Int(500)
})

It("IOPS are set on the block device mapping", func() {
mapping := ngTemplate.Resources["NodeGroupLaunchTemplate"].Properties.LaunchTemplateData.BlockDeviceMappings[0]
Expect(mapping.Ebs["Iops"]).To(Equal(float64(500)))
})
})

Context("ng.VolumeType is GP3", func() {
BeforeEach(func() {
ng.VolumeType = aws.String(api.NodeVolumeTypeGP3)
Expand Down
4 changes: 4 additions & 0 deletions pkg/ctl/cmdutils/configfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,10 @@ func normalizeNodeGroup(ng *api.NodeGroup, l *commonClusterConfigLoader) error {
return fmt.Errorf("%s volume type is not supported via flag --node-volume-type, please use a config file", api.NodeVolumeTypeIO1)
}

if *ng.VolumeType == api.NodeVolumeTypeIO2 {
return fmt.Errorf("%s volume type is not supported via flag --node-volume-type, please use a config file", api.NodeVolumeTypeIO2)
}

normalizeBaseNodeGroup(ng, l.CobraCommand)
return nil
}
Expand Down
Loading