Skip to content

Commit 03eb1b1

Browse files
KeitaWryan-mist
authored andcommitted
fix: nil pointer dereference in CapacityReservationFromEC2 for Interruptible field (aws#9080)
1 parent 537b01a commit 03eb1b1

File tree

2 files changed

+27
-3
lines changed

2 files changed

+27
-3
lines changed

pkg/apis/v1/ec2nodeclass_status.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ func CapacityReservationFromEC2(clk clock.Clock, cr *ec2types.CapacityReservatio
263263
InstanceType: *cr.InstanceType,
264264
OwnerID: *cr.OwnerId,
265265
ReservationType: reservationType,
266-
Interruptible: lo.Ternary(cr.Interruptible == nil, false, *cr.Interruptible),
266+
Interruptible: lo.FromPtrOr(cr.Interruptible, false),
267267
State: state,
268268
}, nil
269269
}

pkg/controllers/nodeclass/capacityreservation_test.go

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,9 +131,33 @@ var _ = Describe("NodeClass Capacity Reservation Reconciler", func() {
131131
ReservationType: ec2types.CapacityReservationTypeDefault,
132132
Interruptible: lo.ToPtr(true),
133133
},
134+
{
135+
AvailabilityZone: lo.ToPtr("test-zone-1a"),
136+
InstanceType: lo.ToPtr("m5.large"),
137+
OwnerId: lo.ToPtr(selfOwnerID),
138+
InstanceMatchCriteria: ec2types.InstanceMatchCriteriaTargeted,
139+
CapacityReservationId: lo.ToPtr("cr-nil-interruptible"),
140+
AvailableInstanceCount: lo.ToPtr[int32](5),
141+
State: ec2types.CapacityReservationStateActive,
142+
ReservationType: ec2types.CapacityReservationTypeDefault,
143+
// Interruptible intentionally omitted (nil) — this is the default
144+
// for standard ODCRs and capacity blocks returned by the EC2 API
145+
},
134146
},
135147
})
136148
})
149+
It("should handle capacity reservations with nil Interruptible field", func() {
150+
nodeClass.Spec.CapacityReservationSelectorTerms = append(nodeClass.Spec.CapacityReservationSelectorTerms, v1.CapacityReservationSelectorTerm{
151+
ID: "cr-nil-interruptible",
152+
})
153+
ExpectApplied(ctx, env.Client, nodeClass)
154+
ExpectObjectReconciled(ctx, env.Client, controller, nodeClass)
155+
nodeClass = ExpectExists(ctx, env.Client, nodeClass)
156+
Expect(nodeClass.StatusConditions().Get(v1.ConditionTypeCapacityReservationsReady).IsTrue()).To(BeTrue())
157+
Expect(nodeClass.Status.CapacityReservations).To(HaveLen(1))
158+
Expect(nodeClass.Status.CapacityReservations[0].ID).To(Equal("cr-nil-interruptible"))
159+
Expect(nodeClass.Status.CapacityReservations[0].Interruptible).To(BeFalse())
160+
})
137161
It("should resolve capacity reservations by ID", func() {
138162
const targetID = "cr-m5.large-1a-1"
139163
nodeClass.Spec.CapacityReservationSelectorTerms = append(nodeClass.Spec.CapacityReservationSelectorTerms, v1.CapacityReservationSelectorTerm{
@@ -206,10 +230,10 @@ var _ = Describe("NodeClass Capacity Reservation Reconciler", func() {
206230
ExpectObjectReconciled(ctx, env.Client, controller, nodeClass)
207231
nodeClass = ExpectExists(ctx, env.Client, nodeClass)
208232
Expect(nodeClass.StatusConditions().Get(v1.ConditionTypeCapacityReservationsReady).IsTrue()).To(BeTrue())
209-
Expect(nodeClass.Status.CapacityReservations).To(HaveLen(5))
233+
Expect(nodeClass.Status.CapacityReservations).To(HaveLen(6))
210234
Expect(lo.Map(nodeClass.Status.CapacityReservations, func(cr v1.CapacityReservation, _ int) string {
211235
return cr.ID
212-
})).To(ContainElements("cr-m5.large-1a-1", "cr-m5.large-1a-2", "cr-p5.48xlarge-1a", "cr-m5.large-1b-1", "cr-m5.large-1b-2"))
236+
})).To(ContainElements("cr-m5.large-1a-1", "cr-m5.large-1a-2", "cr-p5.48xlarge-1a", "cr-m5.large-1b-1", "cr-m5.large-1b-2", "cr-nil-interruptible"))
213237
for _, cr := range nodeClass.Status.CapacityReservations {
214238
Expect(cr.InstanceMatchCriteria).To(Equal("targeted"))
215239
}

0 commit comments

Comments
 (0)