diff --git a/pkg/controllers/nodeclass/validation.go b/pkg/controllers/nodeclass/validation.go index 0266b4737d9b..ff583f11752e 100644 --- a/pkg/controllers/nodeclass/validation.go +++ b/pkg/controllers/nodeclass/validation.go @@ -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" @@ -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 } @@ -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, @@ -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