@@ -21,10 +21,12 @@ import (
2121 "context"
2222 "slices"
2323 "strings"
24+ "time"
2425
2526 "k8s.io/apimachinery/pkg/api/meta"
2627 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2728 "k8s.io/apimachinery/pkg/runtime"
29+ "k8s.io/client-go/util/retry"
2830 ctrl "sigs.k8s.io/controller-runtime"
2931 k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
3032 logger "sigs.k8s.io/controller-runtime/pkg/log"
@@ -64,9 +66,9 @@ func (tc *TraitsController) Reconcile(ctx context.Context, req ctrl.Request) (ct
6466 return ctrl.Result {}, nil
6567 }
6668
67- // ensure HV is ready
68- if ! meta . IsStatusConditionTrue ( hv .Status .Conditions , kvmv1 . ConditionTypeReady ) {
69- return ctrl.Result {}, nil
69+ // ensure hypervisorID is set
70+ if hv .Status .HypervisorID == "" {
71+ return ctrl.Result {RequeueAfter : 10 * time . Second }, nil
7072 }
7173
7274 customTraitsApplied := slices .Collect (func (yield func (string ) bool ) {
@@ -88,14 +90,7 @@ func (tc *TraitsController) Reconcile(ctx context.Context, req ctrl.Request) (ct
8890 // fetch current traits, to ensure we don't add duplicates
8991 current , err := resourceproviders .GetTraits (ctx , tc .serviceClient , hv .Status .HypervisorID ).Extract ()
9092 if err != nil {
91- // set status condition
92- meta .SetStatusCondition (& hv .Status .Conditions , metav1.Condition {
93- Type : ConditionTypeTraitsUpdated ,
94- Status : metav1 .ConditionFalse ,
95- Reason : ConditionTraitsFailed ,
96- Message : err .Error (),
97- })
98- return ctrl.Result {}, tc .Status ().Update (ctx , hv )
93+ return ctrl.Result {}, tc .UpdateStatusCondition (ctx , hv , err , "Failed to get current traits from placement" )
9994 }
10095
10196 var targetTraits []string
@@ -122,26 +117,46 @@ func (tc *TraitsController) Reconcile(ctx context.Context, req ctrl.Request) (ct
122117
123118 if result .Err != nil {
124119 // set status condition
125- meta .SetStatusCondition (& hv .Status .Conditions , metav1.Condition {
126- Type : ConditionTypeTraitsUpdated ,
127- Status : metav1 .ConditionFalse ,
128- Reason : ConditionTraitsFailed ,
129- Message : result .Err .Error (),
130- })
131- return ctrl.Result {}, tc .Status ().Update (ctx , hv )
120+ return ctrl.Result {}, tc .UpdateStatusCondition (ctx , hv , result .Err , "Failed to update traits in placement" )
132121 }
133122 }
134123
135124 // update status
136125 hv .Status .Traits = targetTraits
137- meta .SetStatusCondition (& hv .Status .Conditions , metav1.Condition {
138- Type : ConditionTypeTraitsUpdated ,
139- Status : metav1 .ConditionTrue ,
140- Reason : ConditionTraitsSuccess ,
141- Message : "Traits successfully updated" ,
142- })
126+ return ctrl.Result {}, tc .UpdateStatusCondition (ctx , hv , nil , "Traits successfully updated" )
127+ }
128+
129+ // UpdateStatusCondition updates the TraitsUpdated condition of the Hypervisor status and handles conflicts by retrying.
130+ func (tc * TraitsController ) UpdateStatusCondition (ctx context.Context , orig * kvmv1.Hypervisor , err error , msg string ) error {
131+ return retry .RetryOnConflict (retry .DefaultRetry , func () error {
132+ hv := & kvmv1.Hypervisor {}
133+ if err := tc .Get (ctx , k8sclient .ObjectKeyFromObject (orig ), hv ); err != nil {
134+ return err
135+ }
136+ // set status condition
137+ var reason , message string
138+ var status = metav1 .ConditionTrue
139+ reason = ConditionTraitsSuccess
140+ message = msg
141+
142+ if err != nil {
143+ status = metav1 .ConditionFalse
144+ reason = ConditionTraitsFailed
145+ message = err .Error ()
146+ if msg != "" {
147+ message = msg + ": " + message
148+ }
149+ }
143150
144- return ctrl.Result {}, tc .Status ().Update (ctx , hv )
151+ hv .Status .Traits = orig .Status .Traits
152+ meta .SetStatusCondition (& hv .Status .Conditions , metav1.Condition {
153+ Type : ConditionTypeTraitsUpdated ,
154+ Status : status ,
155+ Reason : reason ,
156+ Message : message ,
157+ })
158+ return tc .Status ().Update (ctx , hv )
159+ })
145160}
146161
147162// SetupWithManager sets up the controller with the Manager.
0 commit comments