Skip to content

Commit 731b521

Browse files
Added EBS IO2 volumeType support to Managed NodeGroup (#7989)
1 parent a3259d6 commit 731b521

File tree

9 files changed

+74
-10
lines changed

9 files changed

+74
-10
lines changed

pkg/apis/eksctl.io/v1alpha5/assets/schema.json

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1576,13 +1576,14 @@
15761576
},
15771577
"volumeType": {
15781578
"type": "string",
1579-
"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.",
1580-
"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.",
1579+
"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.",
1580+
"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.",
15811581
"default": "gp3",
15821582
"enum": [
15831583
"gp2",
15841584
"gp3",
15851585
"io1",
1586+
"io2",
15861587
"sc1",
15871588
"st1"
15881589
]
@@ -1945,13 +1946,14 @@
19451946
},
19461947
"volumeType": {
19471948
"type": "string",
1948-
"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.",
1949-
"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.",
1949+
"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.",
1950+
"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.",
19501951
"default": "gp3",
19511952
"enum": [
19521953
"gp2",
19531954
"gp3",
19541955
"io1",
1956+
"io2",
19551957
"sc1",
19561958
"st1"
19571959
]
@@ -2654,13 +2656,14 @@
26542656
},
26552657
"volumeType": {
26562658
"type": "string",
2657-
"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.",
2658-
"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.",
2659+
"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.",
2660+
"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.",
26592661
"default": "gp3",
26602662
"enum": [
26612663
"gp2",
26622664
"gp3",
26632665
"io1",
2666+
"io2",
26642667
"sc1",
26652668
"st1"
26662669
]

pkg/apis/eksctl.io/v1alpha5/defaults.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,10 @@ func setVolumeDefaults(ng *NodeGroupBase, controlPlaneOnOutposts bool, template
227227
if ng.VolumeIOPS == nil {
228228
ng.VolumeIOPS = aws.Int(DefaultNodeVolumeIO1IOPS)
229229
}
230+
case NodeVolumeTypeIO2:
231+
if ng.VolumeIOPS == nil {
232+
ng.VolumeIOPS = aws.Int(DefaultNodeVolumeIO2IOPS)
233+
}
230234
}
231235

232236
if ng.AMIFamily == NodeImageFamilyBottlerocket && !IsSetAndNonEmptyString(ng.VolumeName) {
@@ -254,6 +258,9 @@ func setDefaultsForAdditionalVolumes(ng *NodeGroupBase, controlPlaneOnOutposts b
254258
if *av.VolumeType == NodeVolumeTypeIO1 && av.VolumeIOPS == nil {
255259
ng.AdditionalVolumes[i].VolumeIOPS = aws.Int(DefaultNodeVolumeIO1IOPS)
256260
}
261+
if *av.VolumeType == NodeVolumeTypeIO2 && av.VolumeIOPS == nil {
262+
ng.AdditionalVolumes[i].VolumeIOPS = aws.Int(DefaultNodeVolumeIO2IOPS)
263+
}
257264
}
258265
}
259266

pkg/apis/eksctl.io/v1alpha5/outposts_validation_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,7 @@ var _ = Describe("Outposts validation", func() {
314314
},
315315
Entry(api.NodeVolumeTypeGP3, api.NodeVolumeTypeGP3, true),
316316
Entry(api.NodeVolumeTypeIO1, api.NodeVolumeTypeIO1, true),
317+
Entry(api.NodeVolumeTypeIO2, api.NodeVolumeTypeIO2, true),
317318
Entry(api.NodeVolumeTypeSC1, api.NodeVolumeTypeSC1, true),
318319
Entry(api.NodeVolumeTypeST1, api.NodeVolumeTypeST1, true),
319320
Entry(api.NodeVolumeTypeGP2, api.NodeVolumeTypeGP2, false),

pkg/apis/eksctl.io/v1alpha5/types.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,8 @@ const (
393393
NodeVolumeTypeGP3 = "gp3"
394394
// NodeVolumeTypeIO1 is Provisioned IOPS SSD
395395
NodeVolumeTypeIO1 = "io1"
396+
// NodeVolumeTypeIO2 is Provisioned IOPS SSD
397+
NodeVolumeTypeIO2 = "io2"
396398
// NodeVolumeTypeSC1 is Cold HDD
397399
NodeVolumeTypeSC1 = "sc1"
398400
// NodeVolumeTypeST1 is Throughput Optimized HDD
@@ -413,6 +415,8 @@ const (
413415
DefaultNodeVolumeThroughput = 125
414416
// DefaultNodeVolumeIO1IOPS defines the default throughput for io1 volumes, set to the min value
415417
DefaultNodeVolumeIO1IOPS = 100
418+
// DefaultNodeVolumeIO2IOPS defines the default throughput for io2 volumes, set to the min value
419+
DefaultNodeVolumeIO2IOPS = 100
416420
// DefaultNodeVolumeGP3IOPS defines the default throughput for gp3, set to the min value
417421
DefaultNodeVolumeGP3IOPS = 3000
418422
)
@@ -536,6 +540,7 @@ func SupportedNodeVolumeTypes() []string {
536540
NodeVolumeTypeGP2,
537541
NodeVolumeTypeGP3,
538542
NodeVolumeTypeIO1,
543+
NodeVolumeTypeIO2,
539544
NodeVolumeTypeSC1,
540545
NodeVolumeTypeST1,
541546
}

pkg/apis/eksctl.io/v1alpha5/validation.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ const (
3131
MaxThroughput = 1000
3232
MinIO1Iops = DefaultNodeVolumeIO1IOPS
3333
MaxIO1Iops = 64000
34+
MinIO2Iops = DefaultNodeVolumeIO2IOPS
35+
MaxIO2Iops = 256000
3436
MinGP3Iops = DefaultNodeVolumeGP3IOPS
3537
MaxGP3Iops = 16000
3638
OneDay = 86400
@@ -774,8 +776,8 @@ func validateNodeGroupBase(np NodePool, path string, controlPlaneOnOutposts bool
774776
func validateVolumeOpts(ng *NodeGroupBase, path string, controlPlaneOnOutposts bool) error {
775777
if ng.VolumeType != nil {
776778
volumeType := *ng.VolumeType
777-
if ng.VolumeIOPS != nil && !(volumeType == NodeVolumeTypeIO1 || volumeType == NodeVolumeTypeGP3) {
778-
return fmt.Errorf("%s.volumeIOPS is only supported for %s and %s volume types", path, NodeVolumeTypeIO1, NodeVolumeTypeGP3)
779+
if ng.VolumeIOPS != nil && !(volumeType == NodeVolumeTypeIO1 || volumeType == NodeVolumeTypeIO2 || volumeType == NodeVolumeTypeGP3) {
780+
return fmt.Errorf("%s.volumeIOPS is only supported for %s, %s and %s volume types", path, NodeVolumeTypeIO1, NodeVolumeTypeIO2, NodeVolumeTypeGP3)
779781
}
780782

781783
if volumeType == NodeVolumeTypeIO1 {
@@ -784,6 +786,12 @@ func validateVolumeOpts(ng *NodeGroupBase, path string, controlPlaneOnOutposts b
784786
}
785787
}
786788

789+
if volumeType == NodeVolumeTypeIO2 {
790+
if ng.VolumeIOPS != nil && !(*ng.VolumeIOPS >= MinIO2Iops && *ng.VolumeIOPS <= MaxIO2Iops) {
791+
return fmt.Errorf("value for %s.volumeIOPS must be within range %d-%d", path, MinIO2Iops, MaxIO2Iops)
792+
}
793+
}
794+
787795
if ng.VolumeThroughput != nil && volumeType != NodeVolumeTypeGP3 {
788796
return fmt.Errorf("%s.volumeThroughput is only supported for %s volume type", path, NodeVolumeTypeGP3)
789797
}

pkg/apis/eksctl.io/v1alpha5/validation_test.go

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,10 +307,34 @@ var _ = Describe("ClusterConfig validation", func() {
307307
})
308308
})
309309

310+
When("VolumeType is io2", func() {
311+
BeforeEach(func() {
312+
*ng0.VolumeType = api.NodeVolumeTypeIO2
313+
})
314+
315+
It("does not fail", func() {
316+
Expect(api.ValidateNodeGroup(0, ng0, cfg)).To(Succeed())
317+
})
318+
319+
When(fmt.Sprintf("the value of volumeIOPS is < %d", api.MinIO2Iops), func() {
320+
It("returns an error", func() {
321+
ng0.VolumeIOPS = aws.Int(api.MinIO2Iops - 1)
322+
Expect(api.ValidateNodeGroup(0, ng0, cfg)).To(MatchError("value for nodeGroups[0].volumeIOPS must be within range 100-256000"))
323+
})
324+
})
325+
326+
When(fmt.Sprintf("the value of volumeIOPS is > %d", api.MaxIO2Iops), func() {
327+
It("returns an error", func() {
328+
ng0.VolumeIOPS = aws.Int(api.MaxIO2Iops + 1)
329+
Expect(api.ValidateNodeGroup(0, ng0, cfg)).To(MatchError("value for nodeGroups[0].volumeIOPS must be within range 100-256000"))
330+
})
331+
})
332+
})
333+
310334
When("VolumeType is one for which IOPS is not supported", func() {
311335
It("returns an error", func() {
312336
*ng0.VolumeType = api.NodeVolumeTypeGP2
313-
Expect(api.ValidateNodeGroup(0, ng0, cfg)).To(MatchError("nodeGroups[0].volumeIOPS is only supported for io1 and gp3 volume types"))
337+
Expect(api.ValidateNodeGroup(0, ng0, cfg)).To(MatchError("nodeGroups[0].volumeIOPS is only supported for io1, io2 and gp3 volume types"))
314338
})
315339
})
316340
})

pkg/cfn/builder/block_device_mapping.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ func makeBlockDeviceMapping(vm *api.VolumeMapping) *gfnec2.LaunchTemplate_BlockD
8484
mapping.Ebs.KmsKeyId = gfnt.NewString(*vm.VolumeKmsKeyID)
8585
}
8686

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

pkg/cfn/builder/nodegroup_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1204,6 +1204,18 @@ var _ = Describe("Unmanaged NodeGroup Template Builder", func() {
12041204
})
12051205
})
12061206

1207+
Context("ng.VolumeType is IO2", func() {
1208+
BeforeEach(func() {
1209+
ng.VolumeType = aws.String(api.NodeVolumeTypeIO1)
1210+
ng.VolumeIOPS = aws.Int(500)
1211+
})
1212+
1213+
It("IOPS are set on the block device mapping", func() {
1214+
mapping := ngTemplate.Resources["NodeGroupLaunchTemplate"].Properties.LaunchTemplateData.BlockDeviceMappings[0]
1215+
Expect(mapping.Ebs["Iops"]).To(Equal(float64(500)))
1216+
})
1217+
})
1218+
12071219
Context("ng.VolumeType is GP3", func() {
12081220
BeforeEach(func() {
12091221
ng.VolumeType = aws.String(api.NodeVolumeTypeGP3)

pkg/ctl/cmdutils/configfile.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -661,6 +661,10 @@ func normalizeNodeGroup(ng *api.NodeGroup, l *commonClusterConfigLoader) error {
661661
return fmt.Errorf("%s volume type is not supported via flag --node-volume-type, please use a config file", api.NodeVolumeTypeIO1)
662662
}
663663

664+
if *ng.VolumeType == api.NodeVolumeTypeIO2 {
665+
return fmt.Errorf("%s volume type is not supported via flag --node-volume-type, please use a config file", api.NodeVolumeTypeIO2)
666+
}
667+
664668
normalizeBaseNodeGroup(ng, l.CobraCommand)
665669
return nil
666670
}

0 commit comments

Comments
 (0)