Skip to content

Commit 01f561b

Browse files
committed
Rely on spec.maintenance=termination instead of terminating
Main motivation is to let anyone set the hypervisor into termination, and for that the spec should be the authorative source for the custom-resource. That means, one can manually offboard the node now by setting that spec too. But also, the terminating condition on the node is not guaranteed to stay, as it is part of the gardener contract. We should keep the use of that to as few places as possible, so if that changes we do not have to rewrite all our code.
1 parent f20183e commit 01f561b

5 files changed

Lines changed: 80 additions & 30 deletions

File tree

internal/controller/aggregates_controller.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ func (ac *AggregatesController) Reconcile(ctx context.Context, req ctrl.Request)
115115
func (ac *AggregatesController) determineDesiredState(hv *kvmv1.Hypervisor) ([]string, metav1.Condition) {
116116
// If terminating AND evicted, remove from all aggregates
117117
// We must wait for eviction to complete before removing aggregates
118-
if meta.IsStatusConditionTrue(hv.Status.Conditions, kvmv1.ConditionTypeTerminating) {
118+
if hv.Spec.Maintenance == kvmv1.MaintenanceTermination {
119119
evictingCondition := meta.FindStatusCondition(hv.Status.Conditions, kvmv1.ConditionTypeEvicting)
120120
// Only remove aggregates if eviction is complete (Evicting=False)
121121
// If Evicting condition is not set or still True, keep current aggregates

internal/controller/aggregates_controller_test.go

Lines changed: 73 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -650,35 +650,86 @@ var _ = Describe("AggregatesController", func() {
650650

651651
Context("when terminating", func() {
652652
BeforeEach(func(ctx SpecContext) {
653-
By("Setting terminating condition")
653+
By("Setting spec.maintenance=termination")
654654
hypervisor := &kvmv1.Hypervisor{}
655655
Expect(k8sClient.Get(ctx, hypervisorName, hypervisor)).To(Succeed())
656-
meta.SetStatusCondition(&hypervisor.Status.Conditions, metav1.Condition{
657-
Type: kvmv1.ConditionTypeTerminating,
658-
Status: metav1.ConditionTrue,
659-
Reason: "dontcare",
660-
Message: "dontcare",
656+
hypervisor.Spec.Maintenance = kvmv1.MaintenanceTermination
657+
Expect(k8sClient.Update(ctx, hypervisor)).To(Succeed())
658+
})
659+
660+
Context("eviction not yet complete", func() {
661+
BeforeEach(func(ctx SpecContext) {
662+
By("Pre-setting the EvictionInProgress condition to match what controller will determine")
663+
hypervisor := &kvmv1.Hypervisor{}
664+
Expect(k8sClient.Get(ctx, hypervisorName, hypervisor)).To(Succeed())
665+
meta.SetStatusCondition(&hypervisor.Status.Conditions, metav1.Condition{
666+
Type: kvmv1.ConditionTypeAggregatesUpdated,
667+
Status: metav1.ConditionFalse,
668+
Reason: kvmv1.ConditionReasonEvictionInProgress,
669+
Message: "Aggregates unchanged while terminating and eviction in progress",
670+
})
671+
Expect(k8sClient.Status().Update(ctx, hypervisor)).To(Succeed())
661672
})
662-
Expect(k8sClient.Status().Update(ctx, hypervisor)).To(Succeed())
663673

664-
By("Pre-setting the EvictionInProgress condition to match what controller will determine")
665-
Expect(k8sClient.Get(ctx, hypervisorName, hypervisor)).To(Succeed())
666-
meta.SetStatusCondition(&hypervisor.Status.Conditions, metav1.Condition{
667-
Type: kvmv1.ConditionTypeAggregatesUpdated,
668-
Status: metav1.ConditionFalse,
669-
Reason: kvmv1.ConditionReasonEvictionInProgress,
670-
Message: "Aggregates unchanged while terminating and eviction in progress",
674+
It("should keep aggregates unchanged and set EvictionInProgress condition", func(ctx SpecContext) {
675+
updated := &kvmv1.Hypervisor{}
676+
Expect(aggregatesController.Client.Get(ctx, hypervisorName, updated)).To(Succeed())
677+
Expect(updated.Status.Aggregates).To(BeEmpty())
678+
Expect(meta.IsStatusConditionFalse(updated.Status.Conditions, kvmv1.ConditionTypeAggregatesUpdated)).To(BeTrue())
679+
cond := meta.FindStatusCondition(updated.Status.Conditions, kvmv1.ConditionTypeAggregatesUpdated)
680+
Expect(cond.Reason).To(Equal(kvmv1.ConditionReasonEvictionInProgress))
671681
})
672-
Expect(k8sClient.Status().Update(ctx, hypervisor)).To(Succeed())
673682
})
674683

675-
It("should neither update Aggregates and nor set status condition", func(ctx SpecContext) {
676-
updated := &kvmv1.Hypervisor{}
677-
Expect(aggregatesController.Client.Get(ctx, hypervisorName, updated)).To(Succeed())
678-
Expect(updated.Status.Aggregates).To(BeEmpty())
679-
Expect(meta.IsStatusConditionFalse(updated.Status.Conditions, kvmv1.ConditionTypeAggregatesUpdated)).To(BeTrue())
680-
cond := meta.FindStatusCondition(updated.Status.Conditions, kvmv1.ConditionTypeAggregatesUpdated)
681-
Expect(cond.Reason).To(Equal(kvmv1.ConditionReasonEvictionInProgress))
684+
Context("eviction complete (regression: aggregates must be cleared)", func() {
685+
BeforeEach(func(ctx SpecContext) {
686+
By("Setting Evicting=False to signal eviction is complete")
687+
hypervisor := &kvmv1.Hypervisor{}
688+
Expect(k8sClient.Get(ctx, hypervisorName, hypervisor)).To(Succeed())
689+
meta.SetStatusCondition(&hypervisor.Status.Conditions, metav1.Condition{
690+
Type: kvmv1.ConditionTypeEvicting,
691+
Status: metav1.ConditionFalse,
692+
Reason: kvmv1.ConditionReasonSucceeded,
693+
Message: "Evicted",
694+
})
695+
hypervisor.Status.Aggregates = []kvmv1.Aggregate{
696+
{Name: "staging", UUID: "uuid-staging"},
697+
{Name: "qa-de-1b", UUID: "uuid-qa-de-1b"},
698+
}
699+
Expect(k8sClient.Status().Update(ctx, hypervisor)).To(Succeed())
700+
701+
By("Mocking GetAggregates and RemoveHost calls")
702+
fakeServer.Mux.HandleFunc("GET /os-aggregates", func(w http.ResponseWriter, r *http.Request) {
703+
w.Header().Add("Content-Type", "application/json")
704+
w.WriteHeader(http.StatusOK)
705+
fmt.Fprint(w, `{
706+
"aggregates": [
707+
{"name": "staging", "id": 1, "uuid": "uuid-staging", "hosts": ["hv-test"]},
708+
{"name": "qa-de-1b", "id": 2, "uuid": "uuid-qa-de-1b", "hosts": ["hv-test"]}
709+
]
710+
}`)
711+
})
712+
fakeServer.Mux.HandleFunc("POST /os-aggregates/1/action", func(w http.ResponseWriter, r *http.Request) {
713+
w.Header().Add("Content-Type", "application/json")
714+
w.WriteHeader(http.StatusOK)
715+
fmt.Fprint(w, `{"aggregate": {"name": "staging", "id": 1, "uuid": "uuid-staging", "hosts": []}}`)
716+
})
717+
fakeServer.Mux.HandleFunc("POST /os-aggregates/2/action", func(w http.ResponseWriter, r *http.Request) {
718+
w.Header().Add("Content-Type", "application/json")
719+
w.WriteHeader(http.StatusOK)
720+
fmt.Fprint(w, `{"aggregate": {"name": "qa-de-1b", "id": 2, "uuid": "uuid-qa-de-1b", "hosts": []}}`)
721+
})
722+
})
723+
724+
It("should remove all aggregates and set Terminating condition", func(ctx SpecContext) {
725+
updated := &kvmv1.Hypervisor{}
726+
Expect(aggregatesController.Client.Get(ctx, hypervisorName, updated)).To(Succeed())
727+
Expect(updated.Status.Aggregates).To(BeEmpty())
728+
Expect(meta.IsStatusConditionFalse(updated.Status.Conditions, kvmv1.ConditionTypeAggregatesUpdated)).To(BeTrue())
729+
cond := meta.FindStatusCondition(updated.Status.Conditions, kvmv1.ConditionTypeAggregatesUpdated)
730+
Expect(cond).NotTo(BeNil())
731+
Expect(cond.Reason).To(Equal(kvmv1.ConditionReasonTerminating))
732+
})
682733
})
683734
})
684735
})

internal/controller/onboarding_controller.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ func (r *OnboardingController) Reconcile(ctx context.Context, req ctrl.Request)
9292
}
9393

9494
// check if hv is terminating
95-
if meta.IsStatusConditionTrue(hv.Status.Conditions, kvmv1.ConditionTypeTerminating) {
95+
if hv.Spec.Maintenance == kvmv1.MaintenanceTermination {
9696
return ctrl.Result{}, r.abortOnboarding(ctx, hv, computeHost)
9797
}
9898

internal/controller/traits_controller.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ func (tc *TraitsController) Reconcile(ctx context.Context, req ctrl.Request) (ct
6969
return ctrl.Result{RequeueAfter: 10 * time.Second}, nil
7070
}
7171

72-
if meta.IsStatusConditionTrue(hv.Status.Conditions, kvmv1.ConditionTypeTerminating) {
72+
if hv.Spec.Maintenance == kvmv1.MaintenanceTermination {
7373
return ctrl.Result{}, nil
7474
}
7575

internal/controller/traits_controller_test.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -280,17 +280,16 @@ var _ = Describe("TraitsController", func() {
280280
})
281281

282282
hypervisor := &kvmv1.Hypervisor{}
283+
Expect(k8sClient.Get(ctx, hypervisorName, hypervisor)).To(Succeed())
284+
hypervisor.Spec.Maintenance = kvmv1.MaintenanceTermination
285+
Expect(k8sClient.Update(ctx, hypervisor)).To(Succeed())
286+
283287
Expect(k8sClient.Get(ctx, hypervisorName, hypervisor)).To(Succeed())
284288
meta.SetStatusCondition(&hypervisor.Status.Conditions, metav1.Condition{
285289
Type: kvmv1.ConditionTypeOnboarding,
286290
Status: metav1.ConditionFalse,
287291
Reason: "UnitTest",
288292
})
289-
meta.SetStatusCondition(&hypervisor.Status.Conditions, metav1.Condition{
290-
Type: kvmv1.ConditionTypeTerminating,
291-
Status: metav1.ConditionTrue,
292-
Reason: "UnitTest",
293-
})
294293
hypervisor.Status.Traits = []string{"CUSTOM_FOO", "HW_CPU_X86_VMX"}
295294
hypervisor.Status.HypervisorID = "1234"
296295
Expect(k8sClient.Status().Update(ctx, hypervisor)).To(Succeed())

0 commit comments

Comments
 (0)