Skip to content

Commit 7aa3395

Browse files
committed
inject reservation requirements
1 parent a978d85 commit 7aa3395

File tree

5 files changed

+34
-17
lines changed

5 files changed

+34
-17
lines changed

pkg/cloudprovider/fake/cloudprovider.go

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import (
4242

4343
func init() {
4444
v1.WellKnownLabels = v1.WellKnownLabels.Insert(v1alpha1.LabelReservationID)
45+
cloudprovider.ReservationIDLabel = v1alpha1.LabelReservationID
4546
}
4647

4748
var _ cloudprovider.CloudProvider = (*CloudProvider)(nil)

pkg/cloudprovider/types.go

+12-5
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ import (
3838
var (
3939
SpotRequirement = scheduling.NewRequirements(scheduling.NewRequirement(v1.CapacityTypeLabelKey, corev1.NodeSelectorOpIn, v1.CapacityTypeSpot))
4040
OnDemandRequirement = scheduling.NewRequirements(scheduling.NewRequirement(v1.CapacityTypeLabelKey, corev1.NodeSelectorOpIn, v1.CapacityTypeOnDemand))
41+
42+
// ReservationIDLabel is a label injected into a reserved offering's requirements which is used to uniquely identify a
43+
// reservation. For example, a reservation could be shared across multiple NodePools, and the value encoded in this
44+
// requirement is used to inform the scheduler that a reservation for one should affect the other.
45+
ReservationIDLabel string
4146
)
4247

4348
type DriftReason string
@@ -258,18 +263,20 @@ type ReservationManager interface {
258263
// these properties are captured with labels in Requirements.
259264
// Requirements are required to contain the keys v1.CapacityTypeLabelKey and corev1.LabelTopologyZone.
260265
type Offering struct {
261-
ReservationID string
266+
Requirements scheduling.Requirements
267+
Price float64
268+
Available bool
262269
ReservationCapacity int
263-
264-
Requirements scheduling.Requirements
265-
Price float64
266-
Available bool
267270
}
268271

269272
func (o *Offering) CapacityType() string {
270273
return o.Requirements.Get(v1.CapacityTypeLabelKey).Any()
271274
}
272275

276+
func (o *Offering) ReservationID() string {
277+
return o.Requirements.Get(ReservationIDLabel).Any()
278+
}
279+
273280
type Offerings []*Offering
274281

275282
// Available filters the available offerings from the returned offerings

pkg/controllers/provisioning/scheduling/nodeclaim.go

+11
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,17 @@ func (n *NodeClaim) FinalizeScheduling() {
230230
// We need nodes to have hostnames for topology purposes, but we don't want to pass that node name on to consumers
231231
// of the node as it will be displayed in error messages
232232
delete(n.Requirements, corev1.LabelHostname)
233+
// If there are any reserved offerings tracked, inject those requirements onto the NodeClaim. This ensures that if
234+
// there are multiple reserved offerings for an instance type, we don't attempt to overlaunch into a single offering.
235+
if len(n.reservedOfferings) != 0 {
236+
n.Requirements.Add(scheduling.NewRequirement(
237+
cloudprovider.ReservationIDLabel,
238+
corev1.NodeSelectorOpIn,
239+
lo.FlatMap(lo.Values(n.reservedOfferings), func(ofs cloudprovider.Offerings, _ int) []string {
240+
return lo.Map(ofs, func(o *cloudprovider.Offering, _ int) string { return o.ReservationID() })
241+
})...,
242+
))
243+
}
233244
}
234245

235246
func (n *NodeClaim) RemoveInstanceTypeOptionsByPriceAndMinValues(reqs scheduling.Requirements, maxPrice float64) (*NodeClaim, error) {

pkg/controllers/provisioning/scheduling/reservationmanager.go

+10-10
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ func NewReservationManager(instanceTypes map[string][]*cloudprovider.InstanceTyp
4141
// If we have multiple offerings with the same reservation ID, track the one with the least capacity. This could be
4242
// the result of multiple nodepools referencing the same capacity reservation, and there being an update to the
4343
// capacity between calls to GetInstanceTypes.
44-
if current, ok := capacity[o.ReservationID]; !ok || current > o.ReservationCapacity {
45-
capacity[o.ReservationID] = o.ReservationCapacity
44+
if current, ok := capacity[o.ReservationID()]; !ok || current > o.ReservationCapacity {
45+
capacity[o.ReservationID()] = o.ReservationCapacity
4646
}
4747
}
4848
}
@@ -55,31 +55,31 @@ func NewReservationManager(instanceTypes map[string][]*cloudprovider.InstanceTyp
5555

5656
func (rm *ReservationManager) Reserve(hostname string, offering *cloudprovider.Offering) bool {
5757
reservations, ok := rm.reservations[hostname]
58-
if ok && reservations.Has(offering.ReservationID) {
58+
if ok && reservations.Has(offering.ReservationID()) {
5959
return true
6060
}
6161
if !ok {
6262
reservations = sets.New[string]()
6363
rm.reservations[hostname] = reservations
6464
}
65-
capacity, ok := rm.capacity[offering.ReservationID]
65+
capacity, ok := rm.capacity[offering.ReservationID()]
6666
if !ok {
6767
// Note: this panic should never occur, and would indicate a serious bug in the scheduling code.
68-
panic(fmt.Sprintf("attempted to reserve non-existent offering with reservation id %q", offering.ReservationID))
68+
panic(fmt.Sprintf("attempted to reserve non-existent offering with reservation id %q", offering.ReservationID()))
6969
}
7070
if capacity == 0 {
7171
return false
7272
}
73-
rm.capacity[offering.ReservationID] -= 1
74-
reservations.Insert(offering.ReservationID)
73+
rm.capacity[offering.ReservationID()] -= 1
74+
reservations.Insert(offering.ReservationID())
7575
return true
7676
}
7777

7878
func (rm *ReservationManager) Release(hostname string, offerings ...*cloudprovider.Offering) {
7979
for _, o := range offerings {
80-
if reservations, ok := rm.reservations[hostname]; ok && reservations.Has(o.ReservationID) {
81-
reservations.Delete(o.ReservationID)
82-
rm.capacity[o.ReservationID] += 1
80+
if reservations, ok := rm.reservations[hostname]; ok && reservations.Has(o.ReservationID()) {
81+
reservations.Delete(o.ReservationID())
82+
rm.capacity[o.ReservationID()] += 1
8383
}
8484
}
8585
}

pkg/controllers/provisioning/scheduling/suite_test.go

-2
Original file line numberDiff line numberDiff line change
@@ -3806,9 +3806,7 @@ var _ = Context("Scheduling", func() {
38063806
}
38073807
reservedInstanceTypes := []*cloudprovider.InstanceType{cloudProvider.InstanceTypes[1], cloudProvider.InstanceTypes[2]}
38083808
for _, it := range reservedInstanceTypes {
3809-
reservationID := fmt.Sprintf("r-%s", it.Name)
38103809
it.Offerings = append(it.Offerings, &cloudprovider.Offering{
3811-
ReservationID: reservationID,
38123810
ReservationCapacity: 1,
38133811
Available: true,
38143812
Requirements: pscheduling.NewLabelRequirements(map[string]string{

0 commit comments

Comments
 (0)