|
| 1 | +# ClusterResourcePlacement Controller Interface Refactor |
| 2 | + |
| 3 | +## Requirements |
| 4 | + |
| 5 | +Refactor the ClusterResourcePlacement controller (`pkg/controllers/clusterresourceplacement/controller.go`) to use interface objects instead of concrete types like ClusterResourcePlacement. Instead, use PlacementObj. The controller should use interface types like BindingObj, ResourceSnapshotObj, and PolicySnapshotObj throughout instead of concrete implementations. |
| 6 | + |
| 7 | +**Specific Requirements**: |
| 8 | +- Replace all function signatures that use `*fleetv1beta1.ClusterResourcePlacement` with `fleetv1beta1.PlacementObj` |
| 9 | +- Replace all concrete types like `*fleetv1beta1.ClusterResourceBinding`, `*fleetv1beta1.ClusterResourceSnapshot`, `*fleetv1beta1.ClusterSchedulingPolicySnapshot` with their respective interface types: `BindingObj`, `ResourceSnapshotObj`, `PolicySnapshotObj` |
| 10 | +- Use helper functions defined in `pkg/utils/controller` when need to get the concrete type from the clusters |
| 11 | +- Update integration and unit tests to work with interface types |
| 12 | +- Follow the patterns established in previous breadcrumb refactoring work, particularly `2025-06-24-0900-rollout-controller-binding-interface-refactor.md` |
| 13 | + |
| 14 | +## Additional comments from user |
| 15 | + |
| 16 | +This follows the breadcrumb protocol and builds on previous successful interface refactoring work. The goal is to make the controller work with both cluster-scoped and namespace-scoped placement objects through unified interfaces. |
| 17 | + |
| 18 | +## Plan |
| 19 | + |
| 20 | +### Phase 1: Analysis and Preparation |
| 21 | +- [x] Task 1.1: Analyze current concrete type usage patterns in the controller.go |
| 22 | +- [x] Task 1.2: Identify all functions that need signature updates for PlacementObj interface |
| 23 | +- [x] Task 1.3: Review available interface methods (PlacementObj, BindingObj, ResourceSnapshotObj, PolicySnapshotObj) |
| 24 | +- [x] Task 1.4: Examine helper functions in pkg/utils/controller for fetching concrete types |
| 25 | +- [x] Task 1.5: Identify test files that will need updates |
| 26 | + |
| 27 | +### Phase 2: Core Reconciler Function Updates |
| 28 | +- [x] Task 2.1: Update `Reconcile` function to use PlacementObj interface ✅ |
| 29 | +- [x] Task 2.2: Update `handleDelete` function signature to use PlacementObj interface ✅ |
| 30 | +- [x] Task 2.3: Update `handleUpdate` function signature to use PlacementObj interface ✅ |
| 31 | +- [x] Task 2.4: Update placement fetch logic to use helper functions from pkg/utils/controller ✅ |
| 32 | + |
| 33 | +### Functions Updated So Far ✅ |
| 34 | +- `Reconcile()` - Now uses `FetchPlacementFromKey()` and works with `PlacementObj` |
| 35 | +- `handleDelete()` - Updated to use `PlacementObj` interface |
| 36 | +- `deleteClusterSchedulingPolicySnapshots()` - Updated to use `PlacementObj` interface |
| 37 | +- `deleteClusterResourceSnapshots()` - Updated to use `PlacementObj` interface |
| 38 | +- `selectResourcesForPlacement()` - Updated to use `PlacementObj` interface |
| 39 | +- `emitPlacementStatusMetric()` - Updated to use `PlacementObj` interface |
| 40 | +- `determineExpectedCRPAndResourcePlacementStatusCondType()` - Updated to use `PlacementObj` interface |
| 41 | +- `handleUpdate()` - COMPLETED ✅ Updated to use `PlacementObj` interface with type assertions for snapshot management |
| 42 | +- `getOrCreateClusterSchedulingPolicySnapshot()` - Updated to accept `PlacementObj` interface |
| 43 | +- `setPlacementStatus()` - Updated to use `PlacementObj` interface |
| 44 | + |
| 45 | +### Phase 3: Update Remaining Utility Functions ✅ |
| 46 | +- [x] Task 3.1: Update `isRolloutCompleted()` function to use PlacementObj interface ✅ |
| 47 | +- [x] Task 3.2: Update `isCRPScheduled()` function to use PlacementObj interface ✅ |
| 48 | +- [x] Task 3.3: Update `buildScheduledCondition()` function to use PlacementObj interface ✅ |
| 49 | +- [x] Task 3.4: Update `buildResourcePlacementStatusMap()` function to use PlacementObj interface ✅ |
| 50 | +- [x] Task 3.5: Update `calculateFailedToScheduleClusterCount()` function to use PlacementObj interface ✅ |
| 51 | + |
| 52 | +### Additional Functions Updated in Phase 3 ✅ |
| 53 | +- `isRolloutCompleted()` - Now uses `PlacementObj` interface with `GetCondition()` and `GetGeneration()` |
| 54 | +- `isCRPScheduled()` - Now uses `PlacementObj` interface with `GetCondition()` and `GetGeneration()` |
| 55 | +- `buildScheduledCondition()` - Now uses `PlacementObj` interface with `GetGeneration()` |
| 56 | +- `buildResourcePlacementStatusMap()` - Now uses `PlacementObj` interface with `GetPlacementStatus()` |
| 57 | +- `calculateFailedToScheduleClusterCount()` - Now uses `PlacementObj` interface with `GetPlacementSpec()` |
| 58 | + |
| 59 | +### Interface Pattern Successfully Established 🎯 |
| 60 | +✅ **No Type Assertions Needed**: All functions now work with `PlacementObj` interface |
| 61 | +✅ **Automatic Interface Satisfaction**: Concrete types (`*ClusterResourcePlacement`) automatically satisfy the interface |
| 62 | +✅ **Clean Separation**: Interface methods (`GetPlacementSpec()`, `GetPlacementStatus()`, `GetCondition()`, `GetGeneration()`) used throughout |
| 63 | +✅ **Future Ready**: Ready to support namespace-scoped placements when they implement the same interface |
| 64 | + |
| 65 | +### Phase 4: Testing and Validation ✅ |
| 66 | +- [x] Task 4.1: Verify unit tests still pass after interface refactoring ✅ |
| 67 | +- [x] Task 4.2: Verify specific refactored functions work correctly ✅ |
| 68 | +- [x] Task 4.3: Ensure no compilation errors ✅ |
| 69 | +- [x] Task 4.4: Validate core functionality maintained ✅ |
| 70 | + |
| 71 | +### Testing Results ✅ |
| 72 | +**Unit Tests**: All existing unit tests continue to pass |
| 73 | +- ✅ `TestBuildResourcePlacementStatusMap` - Passed all sub-tests |
| 74 | +- ✅ `TestGetOrCreateClusterSchedulingPolicySnapshot` - Passed all cases |
| 75 | +- ✅ `TestGetOrCreateClusterResourceSnapshot` - Passed all cases |
| 76 | +- ✅ General controller tests - All passing |
| 77 | + |
| 78 | +**Compilation**: Clean compilation with no errors |
| 79 | +- ✅ `go build ./pkg/controllers/clusterresourceplacement/` - Success |
| 80 | +- ✅ `go test -run ^$` - Compilation-only test passed |
| 81 | + |
| 82 | +**Interface Integration**: All refactored functions work correctly with interfaces |
| 83 | +- ✅ Functions automatically accept concrete types via interface satisfaction |
| 84 | +- ✅ No type assertion issues in main business logic |
| 85 | +- ✅ Error handling preserved and working correctly |
| 86 | + |
| 87 | +### Phase 5: Refactor placement_status.go Functions ⚠️ |
| 88 | +- [ ] Task 5.1: Update `appendFailedToScheduleResourcePlacementStatuses()` to use PlacementObj interface |
| 89 | +- [ ] Task 5.2: Update `appendScheduledResourcePlacementStatuses()` to use PlacementObj and interface types |
| 90 | +- [ ] Task 5.3: Update `buildClusterResourceBindings()` to use PlacementObj and return BindingObj interfaces |
| 91 | +- [ ] Task 5.4: Update `findClusterResourceSnapshotIndexForBindings()` to use interface types |
| 92 | +- [ ] Task 5.5: Update `setResourcePlacementStatusPerCluster()` to use interface types |
| 93 | +- [ ] Task 5.6: Update `setResourcePlacementStatusBasedOnBinding()` to use interface types |
| 94 | + |
| 95 | +### Functions to Refactor in placement_status.go 🎯 |
| 96 | +**Current concrete type usage identified:** |
| 97 | +- `appendFailedToScheduleResourcePlacementStatuses()` - Takes `*ClusterResourcePlacement` |
| 98 | +- `appendScheduledResourcePlacementStatuses()` - Takes `*ClusterResourcePlacement`, `*ClusterSchedulingPolicySnapshot`, `*ClusterResourceSnapshot` |
| 99 | +- `buildClusterResourceBindings()` - Takes `*ClusterResourcePlacement`, `*ClusterSchedulingPolicySnapshot`, returns `map[string]*ClusterResourceBinding` |
| 100 | +- `findClusterResourceSnapshotIndexForBindings()` - Takes `*ClusterResourcePlacement`, `map[string]*ClusterResourceBinding` |
| 101 | +- `setResourcePlacementStatusPerCluster()` - Takes `*ClusterResourcePlacement`, `*ClusterResourceSnapshot`, `*ClusterResourceBinding` |
| 102 | +- `setResourcePlacementStatusBasedOnBinding()` - Takes `*ClusterResourcePlacement`, `*ClusterResourceBinding` |
| 103 | + |
| 104 | +### Phase 3: Snapshot Management Function Updates |
| 105 | +- [ ] Task 3.1: Update `getOrCreateClusterSchedulingPolicySnapshot` to return PolicySnapshotObj |
| 106 | +- [ ] Task 3.2: Update `getOrCreateClusterResourceSnapshot` to return ResourceSnapshotObj |
| 107 | +- [ ] Task 3.3: Update all snapshot listing and deletion functions to use interface types |
| 108 | +- [ ] Task 3.4: Update snapshot creation and management helper functions |
| 109 | + |
| 110 | +### Phase 4: Status and Condition Management Updates |
| 111 | +- [ ] Task 4.1: Update `setPlacementStatus` function to use PlacementObj interface |
| 112 | +- [ ] Task 4.2: Update condition building functions to use interface types |
| 113 | +- [ ] Task 4.3: Update resource placement status calculation functions |
| 114 | + |
| 115 | +### Phase 5: Builder and Utility Function Updates |
| 116 | +- [ ] Task 5.1: Update snapshot builder functions to return interface types |
| 117 | +- [ ] Task 5.2: Update parsing and utility functions to work with interface types |
| 118 | +- [ ] Task 5.3: Update all logging references to use interface objects |
| 119 | + |
| 120 | +### Phase 6: Test Updates |
| 121 | +- [ ] Task 6.1: Update unit tests in the same package to use interface types |
| 122 | +- [ ] Task 6.2: Update integration tests to use interface types |
| 123 | +- [ ] Task 6.3: Run tests to ensure all interface usage is correct |
| 124 | + |
| 125 | +### Phase 7: Interface Method Integration |
| 126 | +- [ ] Task 7.1: Replace direct field access with interface methods where applicable |
| 127 | +- [ ] Task 7.2: Ensure proper use of `GetPlacementSpec()`, `SetPlacementSpec()` methods |
| 128 | +- [ ] Task 7.3: Verify all interface implementations are working correctly |
| 129 | + |
| 130 | +## Analysis |
| 131 | + |
| 132 | +### Current State Analysis ✅ |
| 133 | + |
| 134 | +Based on the grep search, identified 20+ functions that need refactoring: |
| 135 | + |
| 136 | +**Main reconciler functions**: |
| 137 | +- `handleDelete(ctx context.Context, crp *fleetv1beta1.ClusterResourcePlacement)` |
| 138 | +- `handleUpdate(ctx context.Context, crp *fleetv1beta1.ClusterResourcePlacement)` |
| 139 | + |
| 140 | +**Snapshot management functions**: |
| 141 | +- `getOrCreateClusterSchedulingPolicySnapshot(ctx context.Context, crp *fleetv1beta1.ClusterResourcePlacement, revisionHistoryLimit int) (*fleetv1beta1.ClusterSchedulingPolicySnapshot, error)` |
| 142 | +- `getOrCreateClusterResourceSnapshot(ctx context.Context, crp *fleetv1beta1.ClusterResourcePlacement, envelopeObjCount int, resourceSnapshotSpec *fleetv1beta1.ResourceSnapshotSpec, revisionHistoryLimit int) (ctrl.Result, *fleetv1beta1.ClusterResourceSnapshot, error)` |
| 143 | + |
| 144 | +**Builder functions**: |
| 145 | +- `buildMasterClusterResourceSnapshot(...) *fleetv1beta1.ClusterResourceSnapshot` |
| 146 | +- `buildSubIndexResourceSnapshot(...) *fleetv1beta1.ClusterResourceSnapshot` |
| 147 | + |
| 148 | +**Status and condition functions**: |
| 149 | +- `buildScheduledCondition(crp *fleetv1beta1.ClusterResourcePlacement, latestSchedulingPolicySnapshot *fleetv1beta1.ClusterSchedulingPolicySnapshot) metav1.Condition` |
| 150 | +- `buildResourcePlacementStatusMap(crp *fleetv1beta1.ClusterResourcePlacement) map[string][]metav1.Condition` |
| 151 | + |
| 152 | +### Interface Patterns Available ✅ |
| 153 | + |
| 154 | +**PlacementObj interface** provides: |
| 155 | +- `GetPlacementSpec() *ResourcePlacementSpec` |
| 156 | +- `SetPlacementSpec(*ResourcePlacementSpec)` |
| 157 | +- `GetPlacementStatus() *ResourcePlacementStatus` |
| 158 | +- `SetPlacementStatus(*ResourcePlacementStatus)` |
| 159 | + |
| 160 | +**ResourceSnapshotObj interface** provides: |
| 161 | +- `GetResourceSnapshotSpec() *ResourceSnapshotSpec` |
| 162 | +- `SetResourceSnapshotSpec(*ResourceSnapshotSpec)` |
| 163 | +- `GetResourceSnapshotStatus() *ResourceSnapshotStatus` |
| 164 | +- `SetResourceSnapshotStatus(*ResourceSnapshotStatus)` |
| 165 | + |
| 166 | +**PolicySnapshotObj interface** provides: |
| 167 | +- `GetPolicySnapshotSpec() *SchedulingPolicySnapshotSpec` |
| 168 | +- `SetPolicySnapshotSpec(*SchedulingPolicySnapshotSpec)` |
| 169 | +- `GetPolicySnapshotStatus() *SchedulingPolicySnapshotStatus` |
| 170 | +- `SetPolicySnapshotStatus(*SchedulingPolicySnapshotStatus)` |
| 171 | + |
| 172 | +### Helper Functions Available ✅ |
| 173 | + |
| 174 | +From `pkg/utils/controller`: |
| 175 | +- `FetchPlacementFromKey(ctx context.Context, c client.Reader, placementKey queue.PlacementKey) (fleetv1beta1.PlacementObj, error)` |
| 176 | +- `FetchLatestMasterResourceSnapshot(ctx context.Context, k8Client client.Reader, placementKey types.NamespacedName) (fleetv1beta1.ResourceSnapshotObj, error)` |
| 177 | +- Various resolver and conversion helper functions |
| 178 | + |
| 179 | +## Decisions |
| 180 | + |
| 181 | +### Refactoring Strategy |
| 182 | +1. Follow the exact same pattern as the rollout controller refactor in breadcrumb `2025-06-24-0900-rollout-controller-binding-interface-refactor.md` |
| 183 | +2. Replace concrete types with interfaces in function signatures |
| 184 | +3. Use interface methods instead of direct field access |
| 185 | +4. Keep type assertions only at system boundaries (controller-runtime event handling) |
| 186 | +5. Use helper functions from `pkg/utils/controller` for fetching concrete types when needed |
| 187 | + |
| 188 | +### Implementation Order |
| 189 | +1. Start with the main reconciler entry point and work downward |
| 190 | +2. Update function signatures first, then implement interface method usage |
| 191 | +3. Handle tests after core functionality is complete |
| 192 | +4. Follow the principle of minimal changes - avoid large complex refactoring |
| 193 | + |
| 194 | +## Implementation Status |
| 195 | + |
| 196 | +### Analysis Complete ✅ |
| 197 | +- Identified all functions requiring refactoring |
| 198 | +- Confirmed available interface types and methods |
| 199 | +- Located helper functions for type conversion |
| 200 | +- Planned implementation strategy based on successful previous patterns |
| 201 | + |
| 202 | +### Key Understanding ✅ |
| 203 | + |
| 204 | +**Current Controller Logic**: |
| 205 | +1. `Reconcile()` function assumes key is a simple string (cluster-scoped name only) |
| 206 | +2. Directly fetches `ClusterResourcePlacement` using `types.NamespacedName{Name: name}` |
| 207 | +3. Uses concrete types throughout all functions (`*fleetv1beta1.ClusterResourcePlacement`, `*fleetv1beta1.ClusterResourceSnapshot`, etc.) |
| 208 | +4. All business logic operates on concrete types |
| 209 | + |
| 210 | +**Target Interface Pattern**: |
| 211 | +1. `Reconcile()` should accept placement keys that include namespace/name format |
| 212 | +2. Use `FetchPlacementFromKey()` helper to get appropriate placement type (cluster-scoped or namespaced) |
| 213 | +3. Work with `PlacementObj` interface throughout business logic |
| 214 | +4. Use interface methods like `GetPlacementSpec()`, `SetPlacementSpec()` instead of direct field access |
| 215 | +5. Keep type assertions only at system boundaries (controller-runtime interactions) |
| 216 | + |
| 217 | +**Critical Functions That Need Interface Refactoring**: |
| 218 | +- `Reconcile()` - entry point, needs to use placement resolver |
| 219 | +- `handleDelete()` / `handleUpdate()` - core business logic, use PlacementObj |
| 220 | +- `selectResourcesForPlacement()` - resource selection, use PlacementObj |
| 221 | +- `getOrCreateClusterSchedulingPolicySnapshot()` - return PolicySnapshotObj |
| 222 | +- `getOrCreateClusterResourceSnapshot()` - return ResourceSnapshotObj |
| 223 | +- `setPlacementStatus()` - status management, use PlacementObj + interface snapshots |
0 commit comments