Skip to content

Commit a6e567e

Browse files
authored
feat: Convert Staged UpdateRun controller to use interfaces (#272)
1 parent 76ee739 commit a6e567e

File tree

8 files changed

+522
-107
lines changed

8 files changed

+522
-107
lines changed

apis/placement/v1beta1/commons.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,9 @@ const (
145145
// This is used to remember if an "unscheduled" binding was moved from a "bound" state or a "scheduled" state.
146146
PreviousBindingStateAnnotation = FleetPrefix + "previous-binding-state"
147147

148-
// ClusterStagedUpdateRunFinalizer is used by the ClusterStagedUpdateRun controller to make sure that the ClusterStagedUpdateRun
148+
// UpdateRunFinalizer is used by the UpdateRun controller to make sure that the UpdateRun
149149
// object is not deleted until all its dependent resources are deleted.
150-
ClusterStagedUpdateRunFinalizer = FleetPrefix + "stagedupdaterun-finalizer"
150+
UpdateRunFinalizer = FleetPrefix + "stagedupdaterun-finalizer"
151151

152152
// TargetUpdateRunLabel indicates the target update run on a staged run related object.
153153
TargetUpdateRunLabel = FleetPrefix + "targetupdaterun"

pkg/controllers/updaterun/controller.go

Lines changed: 107 additions & 96 deletions
Large diffs are not rendered by default.

pkg/controllers/updaterun/controller_integration_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@ func generateMetricsLabels(
263263
condition, status, reason string,
264264
) []*prometheusclientmodel.LabelPair {
265265
return []*prometheusclientmodel.LabelPair{
266+
{Name: ptr.To("namespace"), Value: &updateRun.Namespace},
266267
{Name: ptr.To("name"), Value: &updateRun.Name},
267268
{Name: ptr.To("generation"), Value: ptr.To(strconv.FormatInt(updateRun.Generation, 10))},
268269
{Name: ptr.To("condition"), Value: ptr.To(condition)},
@@ -662,7 +663,7 @@ func validateUpdateRunHasFinalizer(ctx context.Context, updateRun *placementv1be
662663
if err := k8sClient.Get(ctx, namespacedName, updateRun); err != nil {
663664
return fmt.Errorf("failed to get clusterStagedUpdateRun %s: %w", namespacedName, err)
664665
}
665-
if !controllerutil.ContainsFinalizer(updateRun, placementv1beta1.ClusterStagedUpdateRunFinalizer) {
666+
if !controllerutil.ContainsFinalizer(updateRun, placementv1beta1.UpdateRunFinalizer) {
666667
return fmt.Errorf("finalizer not added to clusterStagedUpdateRun %s", namespacedName)
667668
}
668669
return nil

pkg/controllers/updaterun/execution.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -674,7 +674,7 @@ func markAfterStageRequestCreated(afterStageTaskStatus *placementv1beta1.AfterSt
674674
Status: metav1.ConditionTrue,
675675
ObservedGeneration: generation,
676676
Reason: condition.AfterStageTaskApprovalRequestCreatedReason,
677-
Message: "ClusterApprovalRequest is created",
677+
Message: "ApprovalRequest object is created",
678678
})
679679
}
680680

@@ -685,7 +685,7 @@ func markAfterStageRequestApproved(afterStageTaskStatus *placementv1beta1.AfterS
685685
Status: metav1.ConditionTrue,
686686
ObservedGeneration: generation,
687687
Reason: condition.AfterStageTaskApprovalRequestApprovedReason,
688-
Message: "ClusterApprovalRequest is approved",
688+
Message: "ApprovalRequest object is approved",
689689
})
690690
}
691691

pkg/controllers/updaterun/initialization.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -556,17 +556,18 @@ func (r *Reconciler) recordInitializationSucceeded(ctx context.Context, updateRu
556556
return nil
557557
}
558558

559-
// recordInitializationFailed records the failed initialization condition in the ClusterStagedUpdateRun status.
560-
func (r *Reconciler) recordInitializationFailed(ctx context.Context, updateRun *placementv1beta1.ClusterStagedUpdateRun, message string) error {
561-
meta.SetStatusCondition(&updateRun.Status.Conditions, metav1.Condition{
559+
// recordInitializationFailed records the failed initialization condition in the updateRun status.
560+
func (r *Reconciler) recordInitializationFailed(ctx context.Context, updateRun placementv1beta1.UpdateRunObj, message string) error {
561+
updateRunStatus := updateRun.GetUpdateRunStatus()
562+
meta.SetStatusCondition(&updateRunStatus.Conditions, metav1.Condition{
562563
Type: string(placementv1beta1.StagedUpdateRunConditionInitialized),
563564
Status: metav1.ConditionFalse,
564-
ObservedGeneration: updateRun.Generation,
565+
ObservedGeneration: updateRun.GetGeneration(),
565566
Reason: condition.UpdateRunInitializeFailedReason,
566567
Message: message,
567568
})
568569
if updateErr := r.Client.Status().Update(ctx, updateRun); updateErr != nil {
569-
klog.ErrorS(updateErr, "Failed to update the ClusterStagedUpdateRun status as failed to initialize", "clusterStagedUpdateRun", klog.KObj(updateRun))
570+
klog.ErrorS(updateErr, "Failed to update the updateRun status as failed to initialize", "updateRun", klog.KObj(updateRun))
570571
// updateErr can be retried.
571572
return controller.NewUpdateIgnoreConflictError(updateErr)
572573
}

pkg/metrics/metrics.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ var (
6262
FleetUpdateRunStatusLastTimestampSeconds = prometheus.NewGaugeVec(prometheus.GaugeOpts{
6363
Name: "fleet_workload_update_run_status_last_timestamp_seconds",
6464
Help: "Last update timestamp of update run status in seconds",
65-
}, []string{"name", "generation", "condition", "status", "reason"})
65+
}, []string{"namespace", "name", "generation", "condition", "status", "reason"})
6666
)
6767

6868
var (
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
Copyright 2025 The KubeFleet Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package controller
18+
19+
import (
20+
"context"
21+
22+
"k8s.io/apimachinery/pkg/types"
23+
ctrl "sigs.k8s.io/controller-runtime"
24+
"sigs.k8s.io/controller-runtime/pkg/client"
25+
26+
placementv1beta1 "github.com/kubefleet-dev/kubefleet/apis/placement/v1beta1"
27+
)
28+
29+
// FetchUpdateRunFromRequest resolves a controller runtime request to a concrete update run object that implements UpdateRunObj.
30+
func FetchUpdateRunFromRequest(ctx context.Context, c client.Reader, req ctrl.Request) (placementv1beta1.UpdateRunObj, error) {
31+
var updateRun placementv1beta1.UpdateRunObj
32+
if req.NamespacedName.Namespace != "" {
33+
// This is a namespaced StagedUpdateRun
34+
updateRun = &placementv1beta1.StagedUpdateRun{}
35+
} else {
36+
// This is a cluster-scoped ClusterStagedUpdateRun
37+
updateRun = &placementv1beta1.ClusterStagedUpdateRun{}
38+
}
39+
40+
if err := c.Get(ctx, types.NamespacedName{Namespace: req.NamespacedName.Namespace, Name: req.NamespacedName.Name}, updateRun); err != nil {
41+
return nil, err
42+
}
43+
return updateRun, nil
44+
}

0 commit comments

Comments
 (0)