Skip to content

Commit

Permalink
Added EBS IO2 volumeType support to Managed NodeGroup (#7989)
Browse files Browse the repository at this point in the history
  • Loading branch information
BhowmickSumit authored Feb 6, 2025
1 parent a3259d6 commit 731b521
Show file tree
Hide file tree
Showing 9 changed files with 74 additions and 10 deletions.
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 @@ -1576,13 +1576,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 @@ -1945,13 +1946,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 @@ -2654,13 +2656,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 @@ -314,6 +314,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 @@ -393,6 +393,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 @@ -413,6 +415,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 @@ -536,6 +540,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 @@ -774,8 +776,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 @@ -784,6 +786,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

0 comments on commit 731b521

Please sign in to comment.