Skip to content

Commit

Permalink
Merge pull request #4954 from giantswarm/pr-non-root-volumes
Browse files Browse the repository at this point in the history
✨ Add non root volumes to AWSMachinePool
  • Loading branch information
k8s-ci-robot authored Sep 3, 2024
2 parents ae3323c + 1c956d2 commit abe918c
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 @@ -734,6 +734,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 @@ -522,6 +522,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 @@ -532,9 +534,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 abe918c

Please sign in to comment.