Skip to content

Commit 8edf548

Browse files
committed
Migrate TraitsController to SSA status updates
Replace PatchHypervisorStatusWithRetry with Status().Apply() for ConditionTypeTraitsUpdated and the Traits slice. Error paths pass the current hv.Status.Traits to retain ownership and avoid SSA releasing it on transient placement API failures.
1 parent 42fe079 commit 8edf548

1 file changed

Lines changed: 25 additions & 17 deletions

File tree

internal/controller/traits_controller.go

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,15 @@ import (
2727
"k8s.io/apimachinery/pkg/api/meta"
2828
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2929
"k8s.io/apimachinery/pkg/runtime"
30+
k8sacmetav1 "k8s.io/client-go/applyconfigurations/meta/v1"
3031
ctrl "sigs.k8s.io/controller-runtime"
3132
k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
3233

3334
"github.com/gophercloud/gophercloud/v2"
3435
"github.com/gophercloud/gophercloud/v2/openstack/placement/v1/resourceproviders"
3536

3637
kvmv1 "github.com/cobaltcore-dev/openstack-hypervisor-operator/api/v1"
38+
apiv1 "github.com/cobaltcore-dev/openstack-hypervisor-operator/applyconfigurations/api/v1"
3739
"github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/openstack"
3840
"github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/utils"
3941
)
@@ -103,11 +105,8 @@ func (tc *TraitsController) Reconcile(ctx context.Context, req ctrl.Request) (ct
103105
// fetch current traits, to ensure we don't add duplicates
104106
current, err := resourceproviders.GetTraits(ctx, tc.serviceClient, hv.Status.HypervisorID).Extract()
105107
if err != nil {
106-
condition := getTraitCondition(err, "Failed to get current traits from placement")
107-
patchErr := utils.PatchHypervisorStatusWithRetry(ctx, tc.Client, hv.Name, TraitsControllerName, func(h *kvmv1.Hypervisor) {
108-
meta.SetStatusCondition(&h.Status.Conditions, condition)
109-
})
110-
return ctrl.Result{}, errors.Join(err, patchErr)
108+
return ctrl.Result{}, errors.Join(err,
109+
tc.applyTraitsStatus(ctx, hv, hv.Status.Traits, getTraitCondition(err, "Failed to get current traits from placement")))
111110
}
112111

113112
var targetTraits []string
@@ -131,22 +130,31 @@ func (tc *TraitsController) Reconcile(ctx context.Context, req ctrl.Request) (ct
131130
ResourceProviderGeneration: current.ResourceProviderGeneration,
132131
Traits: targetTraits,
133132
})
134-
err = result.Err
135-
if err != nil {
136-
condition := getTraitCondition(err, "Failed to update traits in placement")
137-
patchErr := utils.PatchHypervisorStatusWithRetry(ctx, tc.Client, hv.Name, TraitsControllerName, func(h *kvmv1.Hypervisor) {
138-
meta.SetStatusCondition(&h.Status.Conditions, condition)
139-
})
140-
return ctrl.Result{}, errors.Join(err, patchErr)
133+
if result.Err != nil {
134+
return ctrl.Result{}, errors.Join(result.Err,
135+
tc.applyTraitsStatus(ctx, hv, hv.Status.Traits, getTraitCondition(result.Err, "Failed to update traits in placement")))
141136
}
142137
}
143138

144139
// update status unconditionally, since we want always to propagate the current traits
145-
err = utils.PatchHypervisorStatusWithRetry(ctx, tc.Client, hv.Name, TraitsControllerName, func(h *kvmv1.Hypervisor) {
146-
h.Status.Traits = targetTraits
147-
meta.SetStatusCondition(&h.Status.Conditions, getTraitCondition(nil, "Traits successfully updated"))
148-
})
149-
return ctrl.Result{}, err
140+
return ctrl.Result{}, tc.applyTraitsStatus(ctx, hv, targetTraits, getTraitCondition(nil, "Traits successfully updated"))
141+
}
142+
143+
func (tc *TraitsController) applyTraitsStatus(ctx context.Context, hv *kvmv1.Hypervisor, traits []string, cond metav1.Condition) error {
144+
statusCfg := apiv1.HypervisorStatus()
145+
statusCfg.Conditions = utils.ConditionsFromStatus(hv.Status.Conditions)
146+
utils.SetApplyConfigurationStatusCondition(&statusCfg.Conditions,
147+
*k8sacmetav1.Condition().
148+
WithType(cond.Type).
149+
WithStatus(cond.Status).
150+
WithReason(cond.Reason).
151+
WithMessage(cond.Message))
152+
if traits != nil {
153+
statusCfg.WithTraits(traits...)
154+
}
155+
return tc.Status().Apply(ctx,
156+
apiv1.Hypervisor(hv.Name, "").WithStatus(statusCfg),
157+
k8sclient.ForceOwnership, k8sclient.FieldOwner(TraitsControllerName))
150158
}
151159

152160
// getTraitCondition creates a Condition object for trait updates

0 commit comments

Comments
 (0)