Skip to content

Commit 7fd6edf

Browse files
author
Arvind Thirumurugan
committed
update recordOverrideSnapshots function
Signed-off-by: Arvind Thirumurugan <[email protected]>
1 parent 26912c5 commit 7fd6edf

File tree

2 files changed

+113
-42
lines changed

2 files changed

+113
-42
lines changed

.github/.copilot/breadcrumbs/2025-09-25-1430-initialize-refactor.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,4 +466,67 @@ func removeWaitTimeFromUpdateRunStatus(updateRun placementv1beta1.StagedUpdateRu
466466
-`computeRunStageStatus`: Fully generic, uses interface-based access patterns
467467
-`generateStagesByStrategy`: Fully generic, uses interface-based access patterns and new strategy resolver utility
468468
-`removeWaitTimeFromUpdateRunStatus`: Fully generic utility function using interface-based approach
469+
470+
### Phase 10: recordOverrideSnapshots Refactor ✅
471+
472+
**Target**: `recordOverrideSnapshots` function - records override snapshots for each cluster in staged update run
473+
474+
**Implementation**: Updated from concrete type to interface-based approach with resource snapshot resolver utilities:
475+
476+
**Before**:
477+
```go
478+
func (r *Reconciler) recordOverrideSnapshots(ctx context.Context, placementName string, updateRun *placementv1beta1.ClusterStagedUpdateRun) error {
479+
// Direct field access
480+
snapshotIndex, err := strconv.Atoi(updateRun.Spec.ResourceSnapshotIndex)
481+
482+
// Manual ClusterResourceSnapshot listing
483+
var masterResourceSnapshot *placementv1beta1.ClusterResourceSnapshot
484+
labelMatcher := client.MatchingLabels{...}
485+
resourceSnapshotList := &placementv1beta1.ClusterResourceSnapshotList{}
486+
err := r.Client.List(ctx, resourceSnapshotList, labelMatcher)
487+
488+
// Direct status access
489+
for _, stageStatus := range updateRun.Status.StagesStatus {
490+
// Direct field modification
491+
}
492+
}
493+
```
494+
495+
**After**:
496+
```go
497+
func (r *Reconciler) recordOverrideSnapshots(ctx context.Context, placementKey types.NamespacedName, updateRun placementv1beta1.StagedUpdateRunObj) error {
498+
// Interface-based access
499+
updateRunSpec := updateRun.GetStagedUpdateRunSpec()
500+
snapshotIndex, err := strconv.Atoi(updateRunSpec.ResourceSnapshotIndex)
501+
502+
// Generic utility function handles type determination
503+
resourceSnapshotList, err := controller.ListAllResourceSnapshotWithAnIndex(ctx, r.Client, updateRunSpec.ResourceSnapshotIndex, placementName, placementKey.Namespace)
504+
505+
// Interface-based status access and update
506+
updateRunStatus := updateRun.GetStagedUpdateRunStatus()
507+
for _, stageStatus := range updateRunStatus.StagesStatus {
508+
// Modify status copy
509+
}
510+
updateRun.SetStagedUpdateRunStatus(*updateRunStatus)
511+
}
512+
```
513+
514+
**Key Improvements**:
515+
1. **Generic Interface Parameters**: Uses `types.NamespacedName` for placement key and `StagedUpdateRunObj` interface
516+
2. **Resource Snapshot Resolver**: Uses `controller.ListAllResourceSnapshotWithAnIndex()` utility function
517+
3. **Interface-Based Access**: Uses `GetStagedUpdateRunSpec()`, `GetStagedUpdateRunStatus()`, `SetStagedUpdateRunStatus()`
518+
4. **Automatic Type Determination**: Namespace presence determines ClusterResourceSnapshot vs ResourceSnapshot
519+
5. **Proper Status Management**: Gets status copy, modifies it, then sets it back
520+
6. **Generic Logging**: Updated terminology from cluster-specific to generic
521+
522+
**Impact**: This function is now fully generic and works with both cluster-scoped and namespace-scoped resources, completing another major piece of the interface-based refactoring.
523+
524+
## Current Status
525+
-`validatePlacement`: Fully generic, uses utility functions and interfaces
526+
-`determinePolicySnapshot`: Fully generic, uses utility functions and interfaces, unnecessary switch removed
527+
-`collectScheduledClusters`: Fully generic, uses utility functions and interfaces
528+
-`computeRunStageStatus`: Fully generic, uses interface-based access patterns
529+
-`generateStagesByStrategy`: Fully generic, uses interface-based access patterns and new strategy resolver utility
530+
-`removeWaitTimeFromUpdateRunStatus`: Fully generic utility function using interface-based approach
531+
-`recordOverrideSnapshots`: Fully generic, uses interface-based access and resource snapshot resolver utilities
469532
- ⚠️ `initialize`: Still takes concrete ClusterStagedUpdateRun type, but now calls interface-based functions

pkg/controllers/updaterun/initialization.go

Lines changed: 50 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -72,15 +72,25 @@ func (r *Reconciler) initialize(
7272
return nil, nil, err
7373
}
7474

75-
// Convert interfaces back to concrete types for compatibility with other functions that haven't been refactored yet
75+
// Compute the stages based on the StagedUpdateStrategy.
76+
// Use interface objects directly - scheduledBindingObjs and toBeDeletedBindingObjs already exist
77+
if err := r.generateStagesByStrategy(ctx, scheduledBindingObjs, toBeDeletedBindingObjs, updateRun); err != nil {
78+
return nil, nil, err
79+
}
80+
// Record the override snapshots associated with each cluster.
81+
if err := r.recordOverrideSnapshots(ctx, placementNamespacedName, updateRun); err != nil {
82+
return nil, nil, err
83+
}
84+
85+
// TODO (arvindth): remove this conversion step after refactoring other functions to use interface types.
86+
// Convert interfaces back to concrete types for compatibility with other functions that haven't been refactored yet.
7687
scheduledBindings := make([]*placementv1beta1.ClusterResourceBinding, len(scheduledBindingObjs))
7788
toBeDeletedBindings := make([]*placementv1beta1.ClusterResourceBinding, len(toBeDeletedBindingObjs))
7889

7990
for i, bindingObj := range scheduledBindingObjs {
8091
if crb, ok := bindingObj.(*placementv1beta1.ClusterResourceBinding); ok {
8192
scheduledBindings[i] = crb
8293
} else {
83-
// This should only happen for StagedUpdateRun with ResourceBinding, but initialize currently only handles ClusterStagedUpdateRun
8494
return nil, nil, fmt.Errorf("expected ClusterResourceBinding but got %T - initialize function needs further refactoring for namespace-scoped resources", bindingObj)
8595
}
8696
}
@@ -93,16 +103,6 @@ func (r *Reconciler) initialize(
93103
}
94104
}
95105

96-
// Compute the stages based on the StagedUpdateStrategy.
97-
// Use interface objects directly - scheduledBindingObjs and toBeDeletedBindingObjs already exist
98-
if err := r.generateStagesByStrategy(ctx, scheduledBindingObjs, toBeDeletedBindingObjs, updateRun); err != nil {
99-
return nil, nil, err
100-
}
101-
// Record the override snapshots associated with each cluster.
102-
if err := r.recordOverrideSnapshots(ctx, placementNamespacedName.Name, updateRun); err != nil {
103-
return nil, nil, err
104-
}
105-
106106
return scheduledBindings, toBeDeletedBindings, r.recordInitializationSucceeded(ctx, updateRun)
107107
}
108108

@@ -516,76 +516,84 @@ func validateAfterStageTask(tasks []placementv1beta1.AfterStageTask) error {
516516
return nil
517517
}
518518

519-
// recordOverrideSnapshots finds all the override snapshots that are associated with each cluster and record them in the ClusterStagedUpdateRun status.
520-
func (r *Reconciler) recordOverrideSnapshots(ctx context.Context, placementName string, updateRun *placementv1beta1.ClusterStagedUpdateRun) error {
519+
// recordOverrideSnapshots finds all the override snapshots that are associated with each cluster and record them in the StagedUpdateRun status.
520+
func (r *Reconciler) recordOverrideSnapshots(ctx context.Context, placementKey types.NamespacedName, updateRun placementv1beta1.StagedUpdateRunObj) error {
521521
updateRunRef := klog.KObj(updateRun)
522522

523-
snapshotIndex, err := strconv.Atoi(updateRun.Spec.ResourceSnapshotIndex)
523+
// Use interface methods to access updateRun spec
524+
updateRunSpec := updateRun.GetStagedUpdateRunSpec()
525+
placementName := placementKey.Name
526+
527+
snapshotIndex, err := strconv.Atoi(updateRunSpec.ResourceSnapshotIndex)
524528
if err != nil || snapshotIndex < 0 {
525-
err := controller.NewUserError(fmt.Errorf("invalid resource snapshot index `%s` provided, expected an integer >= 0", updateRun.Spec.ResourceSnapshotIndex))
526-
klog.ErrorS(err, "Failed to parse the resource snapshot index", "clusterStagedUpdateRun", updateRunRef)
529+
err := controller.NewUserError(fmt.Errorf("invalid resource snapshot index `%s` provided, expected an integer >= 0", updateRunSpec.ResourceSnapshotIndex))
530+
klog.ErrorS(err, "Failed to parse the resource snapshot index", "stagedUpdateRun", updateRunRef)
527531
// no more retries here.
528532
return fmt.Errorf("%w: %s", errInitializedFailed, err.Error())
529533
}
530-
// TODO: use the lib to fetch the master resource snapshot using interface instead of concrete type
531-
var masterResourceSnapshot *placementv1beta1.ClusterResourceSnapshot
532-
labelMatcher := client.MatchingLabels{
533-
placementv1beta1.PlacementTrackingLabel: placementName,
534-
placementv1beta1.ResourceIndexLabel: updateRun.Spec.ResourceSnapshotIndex,
535-
}
536-
resourceSnapshotList := &placementv1beta1.ClusterResourceSnapshotList{}
537-
if err := r.Client.List(ctx, resourceSnapshotList, labelMatcher); err != nil {
538-
klog.ErrorS(err, "Failed to list the clusterResourceSnapshots associated with the clusterResourcePlacement",
539-
"clusterResourcePlacement", placementName, "resourceSnapshotIndex", snapshotIndex, "clusterStagedUpdateRun", updateRunRef)
534+
// Use resource snapshot resolver utility functions to fetch master resource snapshot
535+
// This automatically determines whether to fetch ClusterResourceSnapshot or ResourceSnapshot based on namespace
536+
resourceSnapshotList, err := controller.ListAllResourceSnapshotWithAnIndex(ctx, r.Client, updateRunSpec.ResourceSnapshotIndex, placementName, placementKey.Namespace)
537+
if err != nil {
538+
klog.ErrorS(err, "Failed to list the resourceSnapshots associated with the placement",
539+
"placement", placementKey, "resourceSnapshotIndex", snapshotIndex, "stagedUpdateRun", updateRunRef)
540540
// err can be retried.
541541
return controller.NewAPIServerError(true, err)
542542
}
543543

544-
if len(resourceSnapshotList.Items) == 0 {
545-
err := controller.NewUserError(fmt.Errorf("no clusterResourceSnapshots with index `%d` found for clusterResourcePlacement `%s`", snapshotIndex, placementName))
546-
klog.ErrorS(err, "No specified clusterResourceSnapshots found", "clusterStagedUpdateRun", updateRunRef)
544+
resourceSnapshotObjs := resourceSnapshotList.GetResourceSnapshotObjs()
545+
if len(resourceSnapshotObjs) == 0 {
546+
err := controller.NewUserError(fmt.Errorf("no resourceSnapshots with index `%d` found for placement `%s`", snapshotIndex, placementKey))
547+
klog.ErrorS(err, "No specified resourceSnapshots found", "stagedUpdateRun", updateRunRef)
547548
// no more retries here.
548549
return fmt.Errorf("%w: %s", errInitializedFailed, err.Error())
549550
}
550551

551-
// Look for the master clusterResourceSnapshot.
552-
for i, resourceSnapshot := range resourceSnapshotList.Items {
552+
// Look for the master resourceSnapshot.
553+
var masterResourceSnapshot placementv1beta1.ResourceSnapshotObj
554+
for _, resourceSnapshot := range resourceSnapshotObjs {
553555
// only master has this annotation
554-
if len(resourceSnapshot.Annotations[placementv1beta1.ResourceGroupHashAnnotation]) != 0 {
555-
masterResourceSnapshot = &resourceSnapshotList.Items[i]
556+
if len(resourceSnapshot.GetAnnotations()[placementv1beta1.ResourceGroupHashAnnotation]) != 0 {
557+
masterResourceSnapshot = resourceSnapshot
556558
break
557559
}
558560
}
559561

560-
// No clusterResourceSnapshot found
562+
// No masterResourceSnapshot found
561563
if masterResourceSnapshot == nil {
562-
err := controller.NewUnexpectedBehaviorError(fmt.Errorf("no master clusterResourceSnapshot found for clusterResourcePlacement `%s` with index `%d`", placementName, snapshotIndex))
563-
klog.ErrorS(err, "Failed to find master clusterResourceSnapshot", "clusterStagedUpdateRun", updateRunRef)
564+
err := controller.NewUnexpectedBehaviorError(fmt.Errorf("no master resourceSnapshot found for placement `%s` with index `%d`", placementKey, snapshotIndex))
565+
klog.ErrorS(err, "Failed to find master resourceSnapshot", "stagedUpdateRun", updateRunRef)
564566
// no more retries here.
565567
return fmt.Errorf("%w: %s", errInitializedFailed, err.Error())
566568
}
567-
klog.V(2).InfoS("Found master clusterResourceSnapshot", "clusterResourcePlacement", placementName, "index", snapshotIndex, "clusterStagedUpdateRun", updateRunRef)
569+
klog.V(2).InfoS("Found master resourceSnapshot", "placement", placementKey, "index", snapshotIndex, "stagedUpdateRun", updateRunRef)
568570

569571
// Fetch all the matching overrides.
570-
matchedCRO, matchedRO, err := overrider.FetchAllMatchingOverridesForResourceSnapshot(ctx, r.Client, r.InformerManager, updateRun.Spec.PlacementName, masterResourceSnapshot)
572+
matchedCRO, matchedRO, err := overrider.FetchAllMatchingOverridesForResourceSnapshot(ctx, r.Client, r.InformerManager, updateRunSpec.PlacementName, masterResourceSnapshot)
571573
if err != nil {
572-
klog.ErrorS(err, "Failed to find all matching overrides for the clusterStagedUpdateRun", "masterResourceSnapshot", klog.KObj(masterResourceSnapshot), "clusterStagedUpdateRun", updateRunRef)
574+
klog.ErrorS(err, "Failed to find all matching overrides for the stagedUpdateRun", "masterResourceSnapshot", klog.KObj(masterResourceSnapshot), "stagedUpdateRun", updateRunRef)
573575
// no more retries here.
574576
return fmt.Errorf("%w: %s", errInitializedFailed, err.Error())
575577
}
578+
576579
// Pick the overrides associated with each target cluster.
577-
for _, stageStatus := range updateRun.Status.StagesStatus {
580+
// Use interface methods to access updateRun status
581+
updateRunStatus := updateRun.GetStagedUpdateRunStatus()
582+
for _, stageStatus := range updateRunStatus.StagesStatus {
578583
for i := range stageStatus.Clusters {
579584
clusterStatus := &stageStatus.Clusters[i]
580585
clusterStatus.ClusterResourceOverrideSnapshots, clusterStatus.ResourceOverrideSnapshots, err =
581586
overrider.PickFromResourceMatchedOverridesForTargetCluster(ctx, r.Client, clusterStatus.ClusterName, matchedCRO, matchedRO)
582587
if err != nil {
583-
klog.ErrorS(err, "Failed to pick the override snapshots for cluster", "cluster", clusterStatus.ClusterName, "masterResourceSnapshot", klog.KObj(masterResourceSnapshot), "clusterStagedUpdateRun", updateRunRef)
588+
klog.ErrorS(err, "Failed to pick the override snapshots for cluster", "cluster", clusterStatus.ClusterName, "masterResourceSnapshot", klog.KObj(masterResourceSnapshot), "stagedUpdateRun", updateRunRef)
584589
// no more retries here.
585590
return fmt.Errorf("%w: %s", errInitializedFailed, err.Error())
586591
}
587592
}
588593
}
594+
595+
// Update the status back using interface method
596+
updateRun.SetStagedUpdateRunStatus(*updateRunStatus)
589597
return nil
590598
}
591599

0 commit comments

Comments
 (0)