Skip to content

Commit

Permalink
Add non root volumes to AWSMachinePool
Browse files Browse the repository at this point in the history
  • Loading branch information
mnitchev committed Apr 29, 2024
1 parent 63c6635 commit 1c956d2
Show file tree
Hide file tree
Showing 8 changed files with 145 additions and 5 deletions.
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

0 comments on commit 1c956d2

Please sign in to comment.