func()

in pkg/controllers/nodeclass/validation.go [227:281]


func (v *Validation) validateRunInstancesAuthorization(
	ctx context.Context,
	nodeClass *v1.EC2NodeClass,
	nodeClaim *karpv1.NodeClaim,
	tags map[string]string,
) (reason string, requeue bool, err error) {
	opts, err := v.mockLaunchTemplateOptions(ctx, nodeClaim, nodeClass, tags)
	if err != nil {
		return "", false, fmt.Errorf("generating options, %w", err)
	}

	// We can directly marshal from CreateLaunchTemplate LaunchTemplate data
	runInstancesInput := &ec2.RunInstancesInput{}
	raw, err := json.Marshal(launchtemplate.GetCreateLaunchTemplateInput(ctx, opts, corev1.IPv4Protocol, "").LaunchTemplateData)
	if err != nil {
		return "", false, fmt.Errorf("converting launch template input to run instances input, %w", err)
	}
	if err = json.Unmarshal(raw, runInstancesInput); err != nil {
		return "", false, fmt.Errorf("converting launch template input to run instances input, %w", err)
	}

	// Ensure we set specific values for things that are typically overridden in the CreateFleet call
	runInstancesInput.DryRun = lo.ToPtr(true)
	runInstancesInput.MaxCount = lo.ToPtr[int32](1)
	runInstancesInput.MinCount = lo.ToPtr[int32](1)
	runInstancesInput.NetworkInterfaces[0].SubnetId = lo.ToPtr(nodeClass.Status.Subnets[0].ID)
	runInstancesInput.InstanceType = ec2types.InstanceType(opts.InstanceTypes[0].Name)
	runInstancesInput.TagSpecifications = append(runInstancesInput.TagSpecifications,
		ec2types.TagSpecification{
			ResourceType: ec2types.ResourceTypeInstance,
			Tags:         runInstancesInput.TagSpecifications[0].Tags,
		},
		ec2types.TagSpecification{
			ResourceType: ec2types.ResourceTypeVolume,
			Tags:         runInstancesInput.TagSpecifications[0].Tags,
		},
	)
	// Adding NopRetryer to avoid aggressive retry when rate limited
	if _, err = v.ec2api.RunInstances(ctx, runInstancesInput, func(o *ec2.Options) {
		o.Retryer = aws.NopRetryer{}
	}); awserrors.IgnoreDryRunError(err) != nil {
		// If we get InstanceProfile NotFound, but we have a resolved instance profile in the status,
		// this means there is most likely an eventual consistency issue and we just need to requeue
		if awserrors.IsInstanceProfileNotFound(err) || awserrors.IsRateLimitedError(err) {
			return "", true, nil
		}
		if awserrors.IgnoreUnauthorizedOperationError(err) != nil {
			// Dry run should only ever return UnauthorizedOperation or DryRunOperation so if we receive any other error
			// it would be an unexpected state
			return "", false, fmt.Errorf("validating ec2:RunInstances authorization, %w", err)
		}
		return ConditionReasonRunInstancesAuthFailed, false, nil
	}
	return "", false, nil
}