in pkg/providers/instancetype/offering/offering.go [96:179]
func (p *DefaultProvider) createOfferings(
ctx context.Context,
it *cloudprovider.InstanceType,
nodeClass *v1.EC2NodeClass,
allZones sets.Set[string],
subnetZones map[string]string,
) cloudprovider.Offerings {
var offerings []*cloudprovider.Offering
itZones := sets.New(it.Requirements.Get(corev1.LabelTopologyZone).Values()...)
if ofs, ok := p.cache.Get(p.cacheKeyFromInstanceType(it)); ok {
offerings = append(offerings, ofs.([]*cloudprovider.Offering)...)
} else {
var cachedOfferings []*cloudprovider.Offering
for zone := range allZones {
for _, capacityType := range it.Requirements.Get(karpv1.CapacityTypeLabelKey).Values() {
// Reserved capacity types are constructed separately
if capacityType == karpv1.CapacityTypeReserved {
continue
}
isUnavailable := p.unavailableOfferings.IsUnavailable(ec2types.InstanceType(it.Name), zone, capacityType)
var price float64
var hasPrice bool
switch capacityType {
case karpv1.CapacityTypeOnDemand:
price, hasPrice = p.pricingProvider.OnDemandPrice(ec2types.InstanceType(it.Name))
case karpv1.CapacityTypeSpot:
price, hasPrice = p.pricingProvider.SpotPrice(ec2types.InstanceType(it.Name), zone)
default:
panic(fmt.Sprintf("invalid capacity type %q in requirements for instance type %q", capacityType, it.Name))
}
offering := &cloudprovider.Offering{
Requirements: scheduling.NewRequirements(
scheduling.NewRequirement(karpv1.CapacityTypeLabelKey, corev1.NodeSelectorOpIn, capacityType),
scheduling.NewRequirement(corev1.LabelTopologyZone, corev1.NodeSelectorOpIn, zone),
scheduling.NewRequirement(cloudprovider.ReservationIDLabel, corev1.NodeSelectorOpDoesNotExist),
),
Price: price,
Available: !isUnavailable && hasPrice && itZones.Has(zone),
}
if id, ok := subnetZones[zone]; ok {
offering.Requirements.Add(scheduling.NewRequirement(v1.LabelTopologyZoneID, corev1.NodeSelectorOpIn, id))
}
cachedOfferings = append(cachedOfferings, offering)
}
}
p.cache.SetDefault(p.cacheKeyFromInstanceType(it), cachedOfferings)
offerings = append(offerings, cachedOfferings...)
}
if !options.FromContext(ctx).FeatureGates.ReservedCapacity {
return offerings
}
for i := range nodeClass.Status.CapacityReservations {
if nodeClass.Status.CapacityReservations[i].InstanceType != it.Name {
continue
}
reservation := &nodeClass.Status.CapacityReservations[i]
price := 0.0
if odPrice, ok := p.pricingProvider.OnDemandPrice(ec2types.InstanceType(it.Name)); ok {
// Divide the on-demand price by a sufficiently large constant. This allows us to treat the reservation as "free",
// while maintaining relative ordering for consolidation. If the pricing details are unavailable for whatever reason,
// still succeed to create the offering and leave the price at zero. This will break consolidation, but will allow
// users to utilize the instances they're already paying for.
price = odPrice / 10_000_000.0
}
reservationCapacity := p.capacityReservationProvider.GetAvailableInstanceCount(reservation.ID)
offering := &cloudprovider.Offering{
Requirements: scheduling.NewRequirements(
scheduling.NewRequirement(karpv1.CapacityTypeLabelKey, corev1.NodeSelectorOpIn, karpv1.CapacityTypeReserved),
scheduling.NewRequirement(corev1.LabelTopologyZone, corev1.NodeSelectorOpIn, reservation.AvailabilityZone),
scheduling.NewRequirement(cloudprovider.ReservationIDLabel, corev1.NodeSelectorOpIn, reservation.ID),
),
Price: price,
Available: reservationCapacity != 0 && itZones.Has(reservation.AvailabilityZone),
ReservationCapacity: reservationCapacity,
}
if id, ok := subnetZones[reservation.AvailabilityZone]; ok {
offering.Requirements.Add(scheduling.NewRequirement(v1.LabelTopologyZoneID, corev1.NodeSelectorOpIn, id))
}
offerings = append(offerings, offering)
}
return offerings
}