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 non root volumes to AWSMachinePool #4954

Merged
merged 1 commit into from
Sep 3, 2024
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -738,6 +738,50 @@ spec:
name:
description: The name of the launch template.
type: string
nonRootVolumes:
description: Configuration options for the non root storage volumes.
items:
description: Volume encapsulates the configuration options for
the storage device.
properties:
deviceName:
description: Device name
type: string
encrypted:
description: Encrypted is whether the volume should be encrypted
or not.
type: boolean
encryptionKey:
description: |-
EncryptionKey is the KMS key to use to encrypt the volume. Can be either a KMS key ID or ARN.
If Encrypted is set and this is omitted, the default AWS key will be used.
The key must already exist and be accessible by the controller.
type: string
iops:
description: IOPS is the number of IOPS requested for the
disk. Not applicable to all types.
format: int64
type: integer
size:
description: |-
Size specifies size (in Gi) of the storage device.
Must be greater than the image snapshot size or 8 (whichever is greater).
format: int64
minimum: 8
type: integer
throughput:
description: Throughput to provision in MiB/s supported
for the volume type. Not applicable to all types.
format: int64
type: integer
type:
description: Type is the type of the volume (e.g. gp2, io1,
etc...).
type: string
required:
- size
type: object
type: array
privateDnsName:
description: PrivateDNSName is the options for the instance hostname.
properties:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -730,6 +730,50 @@ spec:
name:
description: The name of the launch template.
type: string
nonRootVolumes:
description: Configuration options for the non root storage volumes.
items:
description: Volume encapsulates the configuration options for
the storage device.
properties:
deviceName:
description: Device name
type: string
encrypted:
description: Encrypted is whether the volume should be encrypted
or not.
type: boolean
encryptionKey:
description: |-
EncryptionKey is the KMS key to use to encrypt the volume. Can be either a KMS key ID or ARN.
If Encrypted is set and this is omitted, the default AWS key will be used.
The key must already exist and be accessible by the controller.
type: string
iops:
description: IOPS is the number of IOPS requested for the
disk. Not applicable to all types.
format: int64
type: integer
size:
description: |-
Size specifies size (in Gi) of the storage device.
Must be greater than the image snapshot size or 8 (whichever is greater).
format: int64
minimum: 8
type: integer
throughput:
description: Throughput to provision in MiB/s supported
for the volume type. Not applicable to all types.
format: int64
type: integer
type:
description: Type is the type of the volume (e.g. gp2, io1,
etc...).
type: string
required:
- size
type: object
type: array
privateDnsName:
description: PrivateDNSName is the options for the instance hostname.
properties:
Expand Down
7 changes: 5 additions & 2 deletions exp/api/v1beta1/conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ package v1beta1

import (
apiconversion "k8s.io/apimachinery/pkg/conversion"
utilconversion "sigs.k8s.io/cluster-api/util/conversion"
"sigs.k8s.io/controller-runtime/pkg/conversion"

infrav1beta1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta1"
infrav1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
infrav1exp "sigs.k8s.io/cluster-api-provider-aws/v2/exp/api/v1beta2"
utilconversion "sigs.k8s.io/cluster-api/util/conversion"
"sigs.k8s.io/controller-runtime/pkg/conversion"
)

// ConvertTo converts the v1beta1 AWSMachinePool receiver to a v1beta2 AWSMachinePool.
Expand Down Expand Up @@ -56,6 +57,7 @@ func (src *AWSMachinePool) ConvertTo(dstRaw conversion.Hub) error {
}

dst.Spec.DefaultInstanceWarmup = restored.Spec.DefaultInstanceWarmup
dst.Spec.AWSLaunchTemplate.NonRootVolumes = restored.Spec.AWSLaunchTemplate.NonRootVolumes

return nil
}
Expand Down Expand Up @@ -101,6 +103,7 @@ func (src *AWSManagedMachinePool) ConvertTo(dstRaw conversion.Hub) error {
dst.Spec.AWSLaunchTemplate = restored.Spec.AWSLaunchTemplate
}
dst.Spec.AWSLaunchTemplate.InstanceMetadataOptions = restored.Spec.AWSLaunchTemplate.InstanceMetadataOptions
dst.Spec.AWSLaunchTemplate.NonRootVolumes = restored.Spec.AWSLaunchTemplate.NonRootVolumes

if restored.Spec.AWSLaunchTemplate.PrivateDNSName != nil {
dst.Spec.AWSLaunchTemplate.PrivateDNSName = restored.Spec.AWSLaunchTemplate.PrivateDNSName
Expand Down
1 change: 1 addition & 0 deletions exp/api/v1beta1/zz_generated.conversion.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 26 additions & 0 deletions exp/api/v1beta2/awsmachinepool_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,31 @@ func (r *AWSMachinePool) validateRootVolume() field.ErrorList {
return allErrs
}

func (r *AWSMachinePool) validateNonRootVolumes() field.ErrorList {
var allErrs field.ErrorList

for _, volume := range r.Spec.AWSLaunchTemplate.NonRootVolumes {
if v1beta2.VolumeTypesProvisioned.Has(string(volume.Type)) && volume.IOPS == 0 {
allErrs = append(allErrs, field.Required(field.NewPath("spec.template.spec.nonRootVolumes.iops"), "iops required if type is 'io1' or 'io2'"))
}

if volume.Throughput != nil {
if volume.Type != v1beta2.VolumeTypeGP3 {
allErrs = append(allErrs, field.Required(field.NewPath("spec.template.spec.nonRootVolumes.throughput"), "throughput is valid only for type 'gp3'"))
}
if *volume.Throughput < 0 {
allErrs = append(allErrs, field.Required(field.NewPath("spec.template.spec.nonRootVolumes.throughput"), "throughput must be nonnegative"))
}
}

if volume.DeviceName == "" {
allErrs = append(allErrs, field.Required(field.NewPath("spec.template.spec.nonRootVolumes.deviceName"), "non root volume should have device name"))
}
}

return allErrs
}

func (r *AWSMachinePool) validateSubnets() field.ErrorList {
var allErrs field.ErrorList

Expand Down Expand Up @@ -124,6 +149,7 @@ func (r *AWSMachinePool) ValidateCreate() (admission.Warnings, error) {

allErrs = append(allErrs, r.validateDefaultCoolDown()...)
allErrs = append(allErrs, r.validateRootVolume()...)
allErrs = append(allErrs, r.validateNonRootVolumes()...)
allErrs = append(allErrs, r.Spec.AdditionalTags.Validate()...)
allErrs = append(allErrs, r.validateSubnets()...)
allErrs = append(allErrs, r.validateAdditionalSecurityGroups()...)
Expand Down
4 changes: 4 additions & 0 deletions exp/api/v1beta2/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ type AWSLaunchTemplate struct {
// +optional
RootVolume *infrav1.Volume `json:"rootVolume,omitempty"`

// Configuration options for the non root storage volumes.
// +optional
NonRootVolumes []infrav1.Volume `json:"nonRootVolumes,omitempty"`

// SSHKeyName is the name of the ssh key to attach to the instance. Valid values are empty string
// (do not use SSH keys), a valid SSH key name, or omitted (use the default SSH key name)
// +optional
Expand Down
7 changes: 7 additions & 0 deletions exp/api/v1beta2/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 14 additions & 3 deletions pkg/cloud/services/ec2/launchtemplate.go
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,8 @@ func (s *Service) createLaunchTemplateData(scope scope.LaunchTemplateScope, imag
data.InstanceMarketOptions = getLaunchTemplateInstanceMarketOptionsRequest(scope.GetLaunchTemplate().SpotMarketOptions)
data.PrivateDnsNameOptions = getLaunchTemplatePrivateDNSNameOptionsRequest(scope.GetLaunchTemplate().PrivateDNSName)

blockDeviceMappings := []*ec2.LaunchTemplateBlockDeviceMappingRequest{}

// Set up root volume
if lt.RootVolume != nil {
rootDeviceName, err := s.checkRootVolume(lt.RootVolume, *data.ImageId)
Expand All @@ -530,9 +532,18 @@ func (s *Service) createLaunchTemplateData(scope scope.LaunchTemplateScope, imag
lt.RootVolume.DeviceName = aws.StringValue(rootDeviceName)

req := volumeToLaunchTemplateBlockDeviceMappingRequest(lt.RootVolume)
data.BlockDeviceMappings = []*ec2.LaunchTemplateBlockDeviceMappingRequest{
req,
}
blockDeviceMappings = append(blockDeviceMappings, req)
}

for vi := range lt.NonRootVolumes {
nonRootVolume := lt.NonRootVolumes[vi]

blockDeviceMapping := volumeToLaunchTemplateBlockDeviceMappingRequest(&nonRootVolume)
blockDeviceMappings = append(blockDeviceMappings, blockDeviceMapping)
}

if len(blockDeviceMappings) > 0 {
data.BlockDeviceMappings = blockDeviceMappings
}

data.TagSpecifications = s.buildLaunchTemplateTagSpecificationRequest(scope, userDataSecretKey)
Expand Down