Skip to content
Draft
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 @@ -662,6 +662,40 @@ spec:
"None": The instance may not make use of any Capacity Reservations. This is to conserve open reservations for desired workloads
"CapacityReservationsOnly": The instance will only run if matched or targeted to a Capacity Reservation
type: string
cpuOptions:
description: |-
CPUOptions defines CPU-related settings for the instance, including the confidential computing policy.
When omitted, this means no opinion and the AWS platform is left to choose a reasonable default.
minProperties: 1
properties:
confidentialCompute:
description: |-
ConfidentialCompute specifies whether confidential computing should be enabled for the instance,
and, if so, which confidential computing technology to use.
Valid values are: Disabled, AMDEncryptedVirtualizationNestedPaging
When set to Disabled, confidential computing will be disabled for the instance.
When set to AMDEncryptedVirtualizationNestedPaging, AMD SEV-SNP will be used as the confidential computing technology for the instance.
In this case, ensure the following conditions are met:
1) The selected instance type supports AMD SEV-SNP.
2) The selected AWS region supports AMD SEV-SNP.
3) The selected AMI supports AMD SEV-SNP.
More details can be checked at https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/sev-snp.html
When omitted, this means no opinion and the AWS platform is left to choose a reasonable default,
which is subject to change without notice. The current default is Disabled.
enum:
- Disabled
- AMDEncryptedVirtualizationNestedPaging
type: string
nestedVirtualization:
description: |-
NestedVirtualization specifies whether to enable nested virtualization on the instance.
Nested virtualization is supported on C8i, M8i, and R8i instance types.
Valid values are: enabled, disabled
enum:
- enabled
- disabled
type: string
type: object
enclaveOptions:
description: EnclaveOptions defines the options for Nitro Enclave
support on the instance.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,40 @@ spec:
"None": The instance may not make use of any Capacity Reservations. This is to conserve open reservations for desired workloads
"CapacityReservationsOnly": The instance will only run if matched or targeted to a Capacity Reservation
type: string
cpuOptions:
description: |-
CPUOptions defines CPU-related settings for the instance, including the confidential computing policy.
When omitted, this means no opinion and the AWS platform is left to choose a reasonable default.
minProperties: 1
properties:
confidentialCompute:
description: |-
ConfidentialCompute specifies whether confidential computing should be enabled for the instance,
and, if so, which confidential computing technology to use.
Valid values are: Disabled, AMDEncryptedVirtualizationNestedPaging
When set to Disabled, confidential computing will be disabled for the instance.
When set to AMDEncryptedVirtualizationNestedPaging, AMD SEV-SNP will be used as the confidential computing technology for the instance.
In this case, ensure the following conditions are met:
1) The selected instance type supports AMD SEV-SNP.
2) The selected AWS region supports AMD SEV-SNP.
3) The selected AMI supports AMD SEV-SNP.
More details can be checked at https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/sev-snp.html
When omitted, this means no opinion and the AWS platform is left to choose a reasonable default,
which is subject to change without notice. The current default is Disabled.
enum:
- Disabled
- AMDEncryptedVirtualizationNestedPaging
type: string
nestedVirtualization:
description: |-
NestedVirtualization specifies whether to enable nested virtualization on the instance.
Nested virtualization is supported on C8i, M8i, and R8i instance types.
Valid values are: enabled, disabled
enum:
- enabled
- disabled
type: string
type: object
enclaveOptions:
description: EnclaveOptions defines the options for Nitro Enclave
support on the instance.
Expand Down
3 changes: 3 additions & 0 deletions exp/api/v1beta1/conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ func (src *AWSMachinePool) ConvertTo(dstRaw conversion.Hub) error {
if preference := restored.Spec.AWSLaunchTemplate.CapacityReservationPreference; preference != "" {
dst.Spec.AWSLaunchTemplate.CapacityReservationPreference = preference
}
dst.Spec.AWSLaunchTemplate.CPUOptions = restored.Spec.AWSLaunchTemplate.CPUOptions

dst.Spec.DefaultInstanceWarmup = restored.Spec.DefaultInstanceWarmup
dst.Spec.AWSLaunchTemplate.NonRootVolumes = restored.Spec.AWSLaunchTemplate.NonRootVolumes
Expand Down Expand Up @@ -143,6 +144,8 @@ func (src *AWSManagedMachinePool) ConvertTo(dstRaw conversion.Hub) error {
if preference := restored.Spec.AWSLaunchTemplate.CapacityReservationPreference; preference != "" {
dst.Spec.AWSLaunchTemplate.CapacityReservationPreference = preference
}

dst.Spec.AWSLaunchTemplate.CPUOptions = restored.Spec.AWSLaunchTemplate.CPUOptions
}
if restored.Spec.AvailabilityZoneSubnetType != nil {
dst.Spec.AvailabilityZoneSubnetType = restored.Spec.AvailabilityZoneSubnetType
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.

5 changes: 5 additions & 0 deletions exp/api/v1beta2/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ type AWSLaunchTemplate struct {
// InstanceType is the type of instance to create. Example: m4.xlarge
InstanceType string `json:"instanceType,omitempty"`

// CPUOptions defines CPU-related settings for the instance, including the confidential computing policy.
// When omitted, this means no opinion and the AWS platform is left to choose a reasonable default.
// +optional
CPUOptions infrav1.CPUOptions `json:"cpuOptions,omitempty,omitzero"`

// RootVolume encapsulates the configuration options for the root volume
// +optional
RootVolume *infrav1.Volume `json:"rootVolume,omitempty"`
Expand Down
1 change: 1 addition & 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.

52 changes: 52 additions & 0 deletions pkg/cloud/services/ec2/launchtemplate.go
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,7 @@ func (s *Service) createLaunchTemplateData(scope scope.LaunchTemplateScope, imag

data := &types.RequestLaunchTemplateData{
InstanceType: types.InstanceType(lt.InstanceType),
CpuOptions: getLaunchTemplateCPUOptionsRequest(lt.CPUOptions),
KeyName: sshKeyNamePtr,
UserData: ptr.To[string](base64.StdEncoding.EncodeToString(userDataForLaunchTemplate)),
}
Expand Down Expand Up @@ -712,6 +713,29 @@ func (s *Service) createLaunchTemplateData(scope scope.LaunchTemplateScope, imag
return data, nil
}

func getLaunchTemplateCPUOptionsRequest(cpuOptions infrav1.CPUOptions) *types.LaunchTemplateCpuOptionsRequest {
request := &types.LaunchTemplateCpuOptionsRequest{}
switch cpuOptions.ConfidentialCompute {
case infrav1.AWSConfidentialComputePolicySEVSNP:
request.AmdSevSnp = types.AmdSevSnpSpecificationEnabled
case infrav1.AWSConfidentialComputePolicyDisabled:
request.AmdSevSnp = types.AmdSevSnpSpecificationDisabled
}

switch cpuOptions.NestedVirtualization {
case infrav1.NestedVirtualizationPolicyEnabled:
request.NestedVirtualization = types.NestedVirtualizationSpecificationEnabled
case infrav1.NestedVirtualizationPolicyDisabled:
request.NestedVirtualization = types.NestedVirtualizationSpecificationDisabled
}

if *request == (types.LaunchTemplateCpuOptionsRequest{}) {
return nil
}

return request
}

func getLaunchTemplateCapacityReservationSpecification(awsLaunchTemplate *expinfrav1.AWSLaunchTemplate) *types.LaunchTemplateCapacityReservationSpecificationRequest {
if awsLaunchTemplate == nil {
return nil
Expand Down Expand Up @@ -916,6 +940,7 @@ func (s *Service) SDKToLaunchTemplate(d types.LaunchTemplateVersion) (*expinfrav
ID: v.ImageId,
},
InstanceType: string(v.InstanceType),
CPUOptions: launchTemplateCPUOptionsFromSDK(v.CpuOptions),
SSHKeyName: v.KeyName,
SpotMarketOptions: SDKToSpotMarketOptions(v.InstanceMarketOptions),
VersionNumber: d.VersionNumber,
Expand Down Expand Up @@ -1009,6 +1034,29 @@ func (s *Service) SDKToLaunchTemplate(d types.LaunchTemplateVersion) (*expinfrav
return i, decodedUserDataHash, launchTemplateUserDataSecretKey, bootstrapDataHash, nil
}

func launchTemplateCPUOptionsFromSDK(cpuOptions *types.LaunchTemplateCpuOptions) infrav1.CPUOptions {
if cpuOptions == nil {
return infrav1.CPUOptions{}
}

result := infrav1.CPUOptions{}
switch cpuOptions.AmdSevSnp {
case types.AmdSevSnpSpecificationEnabled:
result.ConfidentialCompute = infrav1.AWSConfidentialComputePolicySEVSNP
case types.AmdSevSnpSpecificationDisabled:
result.ConfidentialCompute = infrav1.AWSConfidentialComputePolicyDisabled
}

switch cpuOptions.NestedVirtualization {
case types.NestedVirtualizationSpecificationEnabled:
result.NestedVirtualization = infrav1.NestedVirtualizationPolicyEnabled
case types.NestedVirtualizationSpecificationDisabled:
result.NestedVirtualization = infrav1.NestedVirtualizationPolicyDisabled
}

return result
}

// LaunchTemplateNeedsUpdate checks if a new launch template version is needed.
//
// FIXME(dlipovetsky): This check should account for changed userdata, but does not yet do so.
Expand All @@ -1022,6 +1070,10 @@ func (s *Service) LaunchTemplateNeedsUpdate(scope scope.LaunchTemplateScope, inc
return true, services.LaunchTemplateNeedsUpdateReasonInstanceType, nil
}

if !cmp.Equal(incoming.CPUOptions, existing.CPUOptions) {
return true, services.LaunchTemplateNeedsUpdateReasonCPUOptions, nil
}

if !cmp.Equal(incoming.InstanceMetadataOptions, existing.InstanceMetadataOptions) {
return true, services.LaunchTemplateNeedsUpdateReasonInstanceMetadataOptions, nil
}
Expand Down
108 changes: 107 additions & 1 deletion pkg/cloud/services/ec2/launchtemplate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,26 @@ func TestServiceSDKToLaunchTemplate(t *testing.T) {
wantDataSecretKey: nil, // respective tag is not given
wantBootstrapDataHash: nil, // respective tag is not given
},
{
name: "CPU options",
input: ec2types.LaunchTemplateVersion{
LaunchTemplateName: aws.String("foo"),
LaunchTemplateData: &ec2types.ResponseLaunchTemplateData{
CpuOptions: &ec2types.LaunchTemplateCpuOptions{
AmdSevSnp: ec2types.AmdSevSnpSpecificationEnabled,
NestedVirtualization: ec2types.NestedVirtualizationSpecificationEnabled,
},
},
},
wantLT: &expinfrav1.AWSLaunchTemplate{
Name: "foo",
CPUOptions: infrav1.CPUOptions{
ConfidentialCompute: infrav1.AWSConfidentialComputePolicySEVSNP,
NestedVirtualization: infrav1.NestedVirtualizationPolicyEnabled,
},
},
wantUserDataHash: userdata.ComputeHash(nil),
},
{
name: "spot market options",
input: ec2types.LaunchTemplateVersion{
Expand Down Expand Up @@ -723,6 +743,32 @@ func TestServiceLaunchTemplateNeedsUpdate(t *testing.T) {
want: true,
wantNeedsUpdateReason: services.LaunchTemplateNeedsUpdateReasonInstanceType,
},
{
name: "Should return true if incoming CPUOptions differ from existing CPUOptions",
incoming: &expinfrav1.AWSLaunchTemplate{
CPUOptions: infrav1.CPUOptions{
NestedVirtualization: infrav1.NestedVirtualizationPolicyEnabled,
},
},
existing: &expinfrav1.AWSLaunchTemplate{
CPUOptions: infrav1.CPUOptions{
NestedVirtualization: infrav1.NestedVirtualizationPolicyDisabled,
},
},
want: true,
wantNeedsUpdateReason: services.LaunchTemplateNeedsUpdateReasonCPUOptions,
},
{
name: "Should return true if incoming CPUOptions remove existing CPUOptions",
incoming: &expinfrav1.AWSLaunchTemplate{},
existing: &expinfrav1.AWSLaunchTemplate{
CPUOptions: infrav1.CPUOptions{
NestedVirtualization: infrav1.NestedVirtualizationPolicyEnabled,
},
},
want: true,
wantNeedsUpdateReason: services.LaunchTemplateNeedsUpdateReasonCPUOptions,
},
{
name: "new additional security group with filters",
incoming: &expinfrav1.AWSLaunchTemplate{
Expand Down Expand Up @@ -1529,12 +1575,62 @@ var LaunchTemplateVersionIgnoreUnexported = cmpopts.IgnoreUnexported(
ec2types.LaunchTemplateIamInstanceProfileSpecificationRequest{},
ec2types.LaunchTemplateSpotMarketOptionsRequest{},
ec2types.LaunchTemplateInstanceMarketOptionsRequest{},
ec2types.LaunchTemplateCpuOptionsRequest{},
ec2types.Tag{},
ec2types.LaunchTemplateTagSpecificationRequest{},
ec2types.RequestLaunchTemplateData{},
ec2.CreateLaunchTemplateVersionInput{},
)

func TestGetLaunchTemplateCPUOptionsRequest(t *testing.T) {
testCases := []struct {
name string
cpuOptions infrav1.CPUOptions
expectedRequest *ec2types.LaunchTemplateCpuOptionsRequest
}{
{
name: "empty",
expectedRequest: nil,
},
{
name: "enabled nested virtualization",
cpuOptions: infrav1.CPUOptions{
NestedVirtualization: infrav1.NestedVirtualizationPolicyEnabled,
},
expectedRequest: &ec2types.LaunchTemplateCpuOptionsRequest{
NestedVirtualization: ec2types.NestedVirtualizationSpecificationEnabled,
},
},
{
name: "disabled nested virtualization",
cpuOptions: infrav1.CPUOptions{
NestedVirtualization: infrav1.NestedVirtualizationPolicyDisabled,
},
expectedRequest: &ec2types.LaunchTemplateCpuOptionsRequest{
NestedVirtualization: ec2types.NestedVirtualizationSpecificationDisabled,
},
},
{
name: "confidential compute and nested virtualization",
cpuOptions: infrav1.CPUOptions{
ConfidentialCompute: infrav1.AWSConfidentialComputePolicySEVSNP,
NestedVirtualization: infrav1.NestedVirtualizationPolicyEnabled,
},
expectedRequest: &ec2types.LaunchTemplateCpuOptionsRequest{
AmdSevSnp: ec2types.AmdSevSnpSpecificationEnabled,
NestedVirtualization: ec2types.NestedVirtualizationSpecificationEnabled,
},
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
g := NewWithT(t)
g.Expect(getLaunchTemplateCPUOptionsRequest(tc.cpuOptions)).To(Equal(tc.expectedRequest))
})
}
}

func TestCreateLaunchTemplateVersion(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
Expand All @@ -1559,8 +1655,15 @@ func TestCreateLaunchTemplateVersion(t *testing.T) {
marketType ec2types.MarketType
}{
{
name: "Should successfully creates launch template version",
name: "Should successfully create launch template version with CPU options",
awsResourceReference: []infrav1.AWSResourceReference{{ID: aws.String("1")}},
mpScopeUpdater: func(mps *scope.MachinePoolScope) {
spec := mps.AWSMachinePool.Spec
spec.AWSLaunchTemplate.CPUOptions = infrav1.CPUOptions{
NestedVirtualization: infrav1.NestedVirtualizationPolicyEnabled,
}
mps.AWSMachinePool.Spec = spec
},
expect: func(m *mocks.MockEC2APIMockRecorder) {
sgMap := make(map[infrav1.SecurityGroupRole]infrav1.SecurityGroup)
sgMap[infrav1.SecurityGroupNode] = infrav1.SecurityGroup{ID: "1"}
Expand All @@ -1569,6 +1672,9 @@ func TestCreateLaunchTemplateVersion(t *testing.T) {
expectedInput := &ec2.CreateLaunchTemplateVersionInput{
LaunchTemplateData: &ec2types.RequestLaunchTemplateData{
InstanceType: ec2types.InstanceTypeT3Large,
CpuOptions: &ec2types.LaunchTemplateCpuOptionsRequest{
NestedVirtualization: ec2types.NestedVirtualizationSpecificationEnabled,
},
IamInstanceProfile: &ec2types.LaunchTemplateIamInstanceProfileSpecificationRequest{
Name: aws.String("instance-profile"),
},
Expand Down
2 changes: 2 additions & 0 deletions pkg/cloud/services/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ const (
LaunchTemplateNeedsUpdateReasonIamInstanceProfile LaunchTemplateNeedsUpdateReason = "IamInstanceProfile"
// LaunchTemplateNeedsUpdateReasonInstanceType means a difference in the instance type was found.
LaunchTemplateNeedsUpdateReasonInstanceType LaunchTemplateNeedsUpdateReason = "InstanceType"
// LaunchTemplateNeedsUpdateReasonCPUOptions means a difference in the CPU options was found.
LaunchTemplateNeedsUpdateReasonCPUOptions LaunchTemplateNeedsUpdateReason = "CPUOptions"
// LaunchTemplateNeedsUpdateReasonInstanceMetadataOptions means a difference in the instance metadata options was found.
LaunchTemplateNeedsUpdateReasonInstanceMetadataOptions LaunchTemplateNeedsUpdateReason = "InstanceMetadataOptions"
// LaunchTemplateNeedsUpdateReasonSpotMarketOptions means a difference in the spot market options was found.
Expand Down