Skip to content

Commit

Permalink
Pass security groups and subnets into RunInstances dry-run
Browse files Browse the repository at this point in the history
  • Loading branch information
jonathan-innis committed Mar 5, 2025
1 parent 05d086b commit 8d0c188
Showing 1 changed file with 30 additions and 4 deletions.
34 changes: 30 additions & 4 deletions pkg/controllers/nodeclass/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/mitchellh/hashstructure/v2"
"github.com/patrickmn/go-cache"
"github.com/samber/lo"
"sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/reconcile"

"github.com/aws/aws-sdk-go-v2/service/ec2"
Expand Down Expand Up @@ -189,17 +190,25 @@ func (v *Validation) validateRunInstancesAuthorization(
nodeClaim *karpv1.NodeClaim,
tags map[string]string,
) (reason string, err error) {
// NOTE: Since we've already validated the AMI status condition is true, this should never occur
// NOTE: Since we've already validated the status conditions are true, these should never occur
if len(nodeClass.Status.AMIs) == 0 {
return "", fmt.Errorf("no resolved amis in status")
}
if len(nodeClass.Status.Subnets) == 0 {
return "", fmt.Errorf("no resolved subnets in status")
}
if len(nodeClass.Status.SecurityGroups) == 0 {
return "", fmt.Errorf("no resolved security groups in status")
}
if nodeClass.Status.InstanceProfile == "" {
return "", fmt.Errorf("no instance profile in status")
}

var instanceType ec2types.InstanceType
requirements := scheduling.NewNodeSelectorRequirements(nodeClass.Status.AMIs[0].Requirements...)

if requirements.Get(corev1.LabelArchStable).Has(karpv1.ArchitectureAmd64) {
instanceType = ec2types.InstanceTypeM5Large
} else if requirements.Get(corev1.LabelArchStable).Has(karpv1.ArchitectureArm64) {
instanceType = ec2types.InstanceTypeM5Large
if requirements.Get(corev1.LabelArchStable).Has(karpv1.ArchitectureArm64) {
instanceType = ec2types.InstanceTypeM6gLarge
}

Expand All @@ -216,6 +225,10 @@ func (v *Validation) validateRunInstancesAuthorization(
//nolint: gosec
HttpPutResponseHopLimit: lo.ToPtr(int32(lo.FromPtr(nodeClass.Spec.MetadataOptions.HTTPPutResponseHopLimit))),
},
Monitoring: &ec2types.RunInstancesMonitoringEnabled{
// Default Enabled to False if not specified
Enabled: lo.ToPtr(lo.FromPtr(nodeClass.Spec.DetailedMonitoring)),
},
TagSpecifications: []ec2types.TagSpecification{
{
ResourceType: ec2types.ResourceTypeInstance,
Expand All @@ -231,8 +244,21 @@ func (v *Validation) validateRunInstancesAuthorization(
},
},
ImageId: lo.ToPtr(nodeClass.Status.AMIs[0].ID),
IamInstanceProfile: &ec2types.IamInstanceProfileSpecification{
Name: lo.ToPtr(nodeClass.Status.InstanceProfile),
},
// TODO: Need to validate that this doesn't fail if we run out of IPs
NetworkInterfaces: []ec2types.InstanceNetworkInterfaceSpecification{
{
AssociatePublicIpAddress: nodeClass.Spec.AssociatePublicIPAddress,
DeviceIndex: lo.ToPtr[int32](0),
Groups: lo.Map(nodeClass.Status.SecurityGroups, func(s v1.SecurityGroup, _ int) string { return s.ID }),
SubnetId: lo.ToPtr(nodeClass.Status.Subnets[0].ID),
},
},
}

log.FromContext(ctx).Info("Running RunInstances validation")
if _, err := v.ec2api.RunInstances(ctx, runInstancesInput); awserrors.IgnoreDryRunError(err) != nil {
if awserrors.IgnoreUnauthorizedOperationError(err) != nil {
// Dry run should only ever return UnauthorizedOperation or DryRunOperation so if we receive any other error
Expand Down

0 comments on commit 8d0c188

Please sign in to comment.