in pkg/providers/instance/instance.go [236:291]
func (p *DefaultProvider) launchInstance(
ctx context.Context,
nodeClass *v1.EC2NodeClass,
nodeClaim *karpv1.NodeClaim,
capacityType string,
instanceTypes []*cloudprovider.InstanceType,
tags map[string]string,
) (ec2types.CreateFleetInstance, error) {
zonalSubnets, err := p.subnetProvider.ZonalSubnetsForLaunch(ctx, nodeClass, instanceTypes, capacityType)
if err != nil {
return ec2types.CreateFleetInstance{}, cloudprovider.NewCreateError(fmt.Errorf("getting subnets, %w", err), "SubnetResolutionFailed", "Error getting subnets")
}
// Get Launch Template Configs, which may differ due to GPU or Architecture requirements
launchTemplateConfigs, err := p.getLaunchTemplateConfigs(ctx, nodeClass, nodeClaim, instanceTypes, zonalSubnets, capacityType, tags)
if err != nil {
reason, message := awserrors.ToReasonMessage(err)
return ec2types.CreateFleetInstance{}, cloudprovider.NewCreateError(fmt.Errorf("getting launch template configs, %w", err), reason, fmt.Sprintf("Error getting launch template configs: %s", message))
}
if err := p.checkODFallback(nodeClaim, instanceTypes, launchTemplateConfigs); err != nil {
log.FromContext(ctx).Error(err, "failed while checking on-demand fallback")
}
// Create fleet
createFleetInput := GetCreateFleetInput(nodeClass, capacityType, tags, launchTemplateConfigs)
if capacityType == karpv1.CapacityTypeSpot {
createFleetInput.SpotOptions = &ec2types.SpotOptionsRequest{AllocationStrategy: ec2types.SpotAllocationStrategyPriceCapacityOptimized}
} else {
createFleetInput.OnDemandOptions = &ec2types.OnDemandOptionsRequest{AllocationStrategy: ec2types.FleetOnDemandAllocationStrategyLowestPrice}
}
createFleetOutput, err := p.ec2Batcher.CreateFleet(ctx, createFleetInput)
p.subnetProvider.UpdateInflightIPs(createFleetInput, createFleetOutput, instanceTypes, lo.Values(zonalSubnets), capacityType)
if err != nil {
reason, message := awserrors.ToReasonMessage(err)
if awserrors.IsLaunchTemplateNotFound(err) {
for _, lt := range launchTemplateConfigs {
p.launchTemplateProvider.InvalidateCache(ctx, aws.ToString(lt.LaunchTemplateSpecification.LaunchTemplateName), aws.ToString(lt.LaunchTemplateSpecification.LaunchTemplateId))
}
return ec2types.CreateFleetInstance{}, cloudprovider.NewCreateError(fmt.Errorf("launch templates not found when creating fleet request, %w", err), reason, fmt.Sprintf("Launch templates not found when creating fleet request: %s", message))
}
return ec2types.CreateFleetInstance{}, cloudprovider.NewCreateError(fmt.Errorf("creating fleet request, %w", err), reason, fmt.Sprintf("Error creating fleet request: %s", message))
}
p.updateUnavailableOfferingsCache(ctx, createFleetOutput.Errors, capacityType, nodeClaim, instanceTypes)
if len(createFleetOutput.Instances) == 0 || len(createFleetOutput.Instances[0].InstanceIds) == 0 {
requestID, _ := awsmiddleware.GetRequestIDMetadata(createFleetOutput.ResultMetadata)
return ec2types.CreateFleetInstance{}, serrors.Wrap(
combineFleetErrors(createFleetOutput.Errors),
middleware.AWSRequestIDLogKey, requestID,
middleware.AWSOperationNameLogKey, "CreateFleet",
middleware.AWSServiceNameLogKey, "EC2",
middleware.AWSStatusCodeLogKey, 200,
middleware.AWSErrorCodeLogKey, "UnfulfillableCapacity",
)
}
return createFleetOutput.Instances[0], nil
}